2009-05-19 63 views
4

从一个ImageList获取图像时,我患有OutOfMemoryException我一直无法找到问题的合适解决方案。ImageList/Image OutOfMemoryException

我有一个自定义ListView控件,它附加了一个用于绘制ListViewItems的事件。然后调用一个静态方法来设计该项目。

对于大约300个项目的ListView,每次滚动ListView时,我们都会让内存跳到100Mb左右。有问题的代码已经被追查到以下几点:

Image image = item.ImageList.Images[item.ImageKey]; 
if (image != null) 
{ 
    Size imageOffset = new Size((bounds.Width - image.Width)/2, 2); 
    Point imagePosition = bounds.Location + imageOffset; 
    graphics.DrawImageUnscaled(image, imagePosition); 
} 

看来(当然在WinXP)表示,垃圾收集工作不正常,导致内存盘旋。我们尝试添加一个image.Dispose()直接在代码块之后来解决问题,但这没有任何作用。

到目前为止我设法找到的唯一解决方案是在调用GC.Collect()的静态方法的末尾。然而,这个问题是,它会导致ListView缓慢地重新绘制自己,并且当它试图重新绘制时,最终会在屏幕上出现工件。

有没有其他人经历过这个?或者知道解决方法?

+0

我已经经历了两个不同的应用程序,他们都不涉及图像或ListView outofmemoryexceptions。不幸的是,我能够找到的唯一解决方案是经常调用GC.Collect()。 – Crispy 2009-05-19 13:36:07

回答

4

您正在处置graphics?此外,它像你提到的那样处理你的图像,然后你需要确保它被从ImageList中取出,否则会引发更多问题。图像的格式是什么?

一般而言,当涉及图像时出现内存不足问题时,您的问题将是某种方法不喜欢某种图像格式,或者9/10次,您误解了其中一个图形对象的生命周期。

  • 检查所有的Graphics的用法,并把它们放在using块。
  • 检查Image生命周期,并小心将其复制,处置他们,收盘底层流等
  • 加载了一个内存管理器(VS2008有一个内置),看看有什么是没有得到清理很好。

编辑:

这是我能找到,使用ImageList.Draw (graphics, x, y, width, height, index)的最佳选择。这将使用内部手柄,而不是创建图像的副本。

+0

感谢您的回复。这是关于图像配置的一个好处,我可能需要删除该行,然后离开垃圾收集。 我不想放弃图形对象,因为我从EventArgs中抓取它,因此我不知道它是否会在其他地方使用。 图像各不相同,我们发现它的时间是一个图标文件,所以我们使用Icon.ToBitmap()。 将试图追查内存管理器,这听起来非常有用。 – Ian 2009-05-20 08:05:59

0

我已经成功解决了我的应用程序中的这个问题。

杰森有答案,你必须确保你使用“使用”块,或他们的等价物。

我使用VB,等价的是使用Try ... Catch ...最后,每当我创建一个新的位图,调用BitMap.Dispose并在“Finally”部分中设置Bitmap = Nothing。

这似乎是一个非常普遍的问题,从我花在Google上的这段时间来看。下面的代码还允许任何图像在缩小到缩略图时保留其纵横比,这对Google来说似乎很难实现!

代码:

Private Function AspectedImage(ByVal ImagePath As String, ByVal SizeWanted As Integer) As Image 

    Dim myBitmap, WhiteSpace As System.Drawing.Bitmap 
    Dim myGraphics As Graphics 
    Dim myDestination As Rectangle 
    Dim MaxDimension As Integer 
    Dim ReductionRatio As Double 

    Try 

     'create an instance of bitmap based on a file 
     myBitmap = New System.Drawing.Bitmap(ImagePath) 



     'create a new square blank bitmap the right size 
     If myBitmap.Height >= myBitmap.Width Then MaxDimension = myBitmap.Height Else MaxDimension = myBitmap.Width 
     ReductionRatio = SizeWanted/MaxDimension 
     WhiteSpace = New System.Drawing.Bitmap(SizeWanted, SizeWanted) 

     'get the drawing surface of the new blank bitmap 
     myGraphics = Graphics.FromImage(WhiteSpace) 

     'find out if the photo is landscape or portrait 
     Dim WhiteGap As Double 

     If myBitmap.Height > myBitmap.Width Then 'portrait 
      WhiteGap = ((myBitmap.Width - myBitmap.Height)/2) * -1 
      myDestination = New Rectangle(x:=CInt(WhiteGap * ReductionRatio), y:=0, Width:=Int(myBitmap.Width * ReductionRatio), Height:=Int(myBitmap.Height * ReductionRatio)) 
     Else 'landscape 
      WhiteGap = ((myBitmap.Width - myBitmap.Height)/2) 
      'create a destination rectangle 
      myDestination = New Rectangle(x:=0, y:=CInt(WhiteGap * ReductionRatio), Width:=Int(myBitmap.Width * ReductionRatio), Height:=Int(myBitmap.Height * ReductionRatio)) 
     End If 

     'draw the image on the white square 
     myGraphics.DrawImage(image:=myBitmap, rect:=myDestination) 
     AspectedImage = WhiteSpace 

    Catch ex As Exception 
     myBitmap = New System.Drawing.Bitmap("") 
     AspectedImage = New System.Drawing.Bitmap(4, 4) 
     ImageBufferExceeded = True 
     MsgBox("Image Buffer exceeded, too many images in memory. If the one(s) you want can't be seen, please restart the application and navigate straight to your images") 
    Finally 
     myBitmap.Dispose() 
     myBitmap = Nothing 
     WhiteSpace = Nothing 
    End Try 

End Function