从ImageList获取图像时,我遇到OutOfMemoryException我一直无法找到问题的合适解决方案。
我有一个Custom 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 :(得分:4)
你在处理graphics
吗?此外,您按照提到的方式处理图像,然后您需要确保将其从ImageList中取出,否则会导致更多问题。图像的格式是什么?
一般情况下,当涉及图像时出现内存不足问题,您的问题将是某些方法不喜欢某种图像格式,或者9/10次,您误解了其中一个图形对象的生命周期。
Graphics
用法,并将其放入using
块。Image
生命周期,小心复制,处理它们,关闭底层流等等。编辑:
这是我能找到的最佳选择,使用ImageList.Draw(graphics, x, y, width, height, index)
。这将使用内部句柄,而不是创建图像的副本。
答案 1 :(得分:0)
我已经设法在我的应用程序中解决了这个问题。
Jason有答案,你必须确保你使用“使用”块或它们的等价物。
我使用VB,相当于使用Try ... Catch ...最后每当我创建一个新的位图时,调用BitMap.Dispose并在“Finally”部分设置Bitmap = nothing。
这似乎是一个非常普遍的问题,从我尝试使用谷歌这几个小时来判断。下面的代码还允许任何图像在缩小为缩略图时保持其宽高比,这是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