ImageList / Image OutOfMemoryException

I get an OutOfMemoryException when getting an image from an ImageList. I could not find a suitable solution to the problem.

I have a Custom ListView control that bound an event to it to draw ListViewItems. Then it calls the static method, which is designed to draw the element.

For a ListView of about 300 elements, we get that the memory grows by about 100 MB every time the ListView scrolls. The violation code was tracked until the following:

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); } 

It seems (of course, on WinXP) that garbage collection does not work correctly, forcing memory spirally. We tried to add the .Dispose () image immediately after the code block to fix the problem, but this has no effect.

The only solution that I have been able to find so far is at the end of the static method for calling GC.Collect (). However, the problem is that after this ListView re-paints itself slowly, and you get artifacts on the screen while it tries to re-draw.

Has anyone else experienced this? Or knows about a workaround?

+4
source share
2 answers

Do you manage graphics ? In addition, you have your image as you mentioned, then you need to make sure that it is removed from the ImageList or you will cause more problems. What format are the images?

In the general case, when you have memory problems when dealing with images, your problem will be either in some way, or in some image format, or 9/10 times, you misunderstood the life cycle of one of the graphic objects.

  • Check all your graphics and put them in using .
  • Check the Image life cycle and be careful with copying, deleting, closing main threads, etc.
  • Download the memory manager (VS2008 has one built-in) and see what doesn't clean up nicely.

EDIT:

Here is the best option I can find, use ImageList.Draw (graphics, x, y, width, height, index) . This will use an internal descriptor instead of creating a copy of the image.

+4
source

I was able to solve this problem in my application.

Jason has the answer, you have to make sure you use the "use" of the blocks or their equivalent.

I use VB, and the equivalent was to use Try ... Catch ... Finally, when I created a new bitmap, calling BitMap.

This is apparently a very common problem, judging by the hours I spent trying Google. The code below also allows any image to maintain aspect ratio when reduced to a thumbnail, which is even worse than Google!

code:

 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 
0
source

All Articles