automaton1234

To implement an image thumbnail viewer, I have used a ListView control that uses a LargeImageList, and has OwnerDraw set to true. I've also added the following event handler to draw the image manually, for certain reasons:

private void ListViewEx_DrawItem(object sender,
DrawListViewItemEventArgs e)
{
ListView lv = sender as ListView;
if (lv.LargeImageList == null)
return;

int nImage = e.Item.ImageIndex;
if (nImage < 0 || nImage >= lv.LargeImageList.Images.Count)
return;

// PROBLEM line:

Image img = lv.LargeImageList.Images[nImage];
Rectangle rSrce = new Rectangle(0, 0,
img.Width, img.Height);
Rectangle rDest = e.Bounds;
e.Graphics.DrawImage(img, rDest, rSrce, GraphicsUnit.Pixel);
}

My issue is that when each DrawItem event occurs, I can see the memory usage in TaskManager increasing very
rapidly. If I just create a new empty Image on the "PROBLEM" line then it's fine.

So, it appears that just getting an Image reference from LargeImageList leaves many large objects lying around.

Any suggestions would be appreciated.



Re: Windows Forms General Memory usage of ListView's LargeImageList, when using OwnerDraw and DrawItem event

OmegaMan

The taskmanager view of an applications memory requirements is actually an amalgamation of differing memory views of the the program. There are also differing factors that are under the hood which are conspiring against someone just looking at a general memory pictures. Such things as:

  1. The OS will allocate more room that what is actually needed so an app can grow without incrementally without having to allocate for more space for each request.
  2. The OS will keep an applications memory footprint around with the expectation that the app will eventually need the memory. That scenario is that the app requests X amount of memory, and it is granted. The app then releases the memory and the GC cleans it up. The OS will keep the footprint alive for some time with the expectation that the app may need to regrow to the footprint size. That provides effencies, which would not be realized if the app breathed memory; expanding and substracting, its better just to keep it full, for the app, specially if the OS is not stressed from other applications needing memory.
  3. Large objects over 85K will fall into the Large Object Heap which is not collected like the smaller brethren and will make a program stay large for longer times.
  4. Unhooked event subscriptions will pin an object and have to be manually unsubscribed in the dispose, otherwise an object can live on ...even though its been unreferenced.
I recommend that you look into perfmon and monitor private bytes and GC for a better view of what you are looking at. Here is some reading which will help:

Here are some things to read up on:





Re: Windows Forms General Memory usage of ListView's LargeImageList, when using OwnerDraw and DrawItem event

automaton1234

A bit of a stock answer there, but thanks anyway

The point that I should have made was that the quoted code rapidly achieves an OutOfMemoryException, which implies that large objects are being created which cannot be freed.

I was assuming that creating an Image reference like that would not allocate anything. For example, when the "Image img = lv.LargeImageList.Images[nImage];" line is replaced with "Image img = new Bitmap(2048, 2048);", then no OutOfMemoryException occurs, which is what I would expect.

I'll read up on how ImageLists work in conjunction with ListView controls - perhaps it is related to some internal event or other.


Thanks.





Re: Windows Forms General Memory usage of ListView's LargeImageList, when using OwnerDraw and DrawItem event

OmegaMan

What you see is correct that large objects are not being freed like their smaller brethren. What I believe you are running into is that the objects you are working with are greater than 85K and objects of those size are being created in the Large Object Heap (LOH). The LOH is not as aggressively garbaged collected as the standard heap and it sounds like you are quickly running out of memory. Here are your options

  1. Reuse the image that was created by placing the new image within it.
  2. Check for any possible out of memory issues nd work around, that exception from happening by testing the memory footprint before committing a big object to be created. See the article MemoryFailPoint Class with its excellent example on its usage. That will help avoid and work around memory problems as memory is being allocated and disposed dynamically.
Whats wrong with stock answers. <g> Good Luck HTH