cgraus

Hi all. I am putting the finishing touches on my beta release, and I'm starting to look at memory usage. My app shows images, and we have 1/2/4 pane views. They are independant of one another, so we can have 7 images loaded. We also support labels and because I couldn't get labels as controls to lineup properly, we create a second bitmap to show the iamge with labels, so a possible 14 images loaded. That would be rare, most images do not have labels, and I'm controlling the image count as much as I can.

My app reloads the images as you zoom, so we do a resize and keep images in memory at the required size only. I note that these classes do not have Dspose methods, as my users move between images, what can I do to make sure that memory is cleaned up I did the same sequence in my app 3 tmes and got usage figures between 250MB and 750MB. Also, as I only show either the non-label or the label image, they are stored as members of type BitmapSource. Will that cache the image effectively until it's made the source of a control ( remembering that they go back and forth ), or should I find a way to store in memory as, say, a jpeg and convert to a raw image when I show it

My core imaging code looks like this:

BitmapImage bi = biDefault;

// read raw bytes from my DB file

MediaDBFileReader dbReader = new MediaDBFileReader(dbName);

byte[] fileBuffer = dbReader.ReadFile(physicalFilePath);

if (fileBuffer != null)

{

bi = new BitmapImage();

bi.BeginInit();

bi.StreamSource = new MemoryStream(fileBuffer);

bi.EndInit();

if ( !(width == -1 && height == -1) )

{

fullHeight = bi.PixelHeight;

fullWidth = bi.PixelWidth;

height = Math.Min(height, fullHeight);

double scale = height / fullHeight;

TransformedBitmap scaled = new TransformedBitmap(bi, new ScaleTransform(scale, scale));

return scaled as BitmapSource;

}

}

Then in the main code, I pass this BitmapSource to a method that creates a new bitmap from it using the RenderTargetBitmap class to create first an image that is 4:3 ( so it sizes the same as the labels, which need to be 4:3 ), and then the image with the labels on it. this occurs the first time I ask for labels, then both are kept as members and the source is swapped as you turn them on or off.

Any insight in to ways I can be aggressive in managing memory would be greatly appreciated.

Christian




Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

Dr. WPF

I honestly don't know how much of this will be applicable to your scenario...

When I was working on an image-intensive application, I ran into similar memory issues. As my app would run, the memory would continuously grow and it seemed like the garbage collector either never kicked in or something was keeping rooted references to the images long beyond their required lifetime.

After implementing a custom caching solution and a few changes described below, my memory usage went from 350MB and climbing to 80MB and steady.

Originally, my Image elements had a binding on the Source property that pointed to a binary field in my data table. A value converter was being used to create the BitmapImage at the required size. I decided this involved too much processing (the images were constantly being regenerated), so I implemented an ImageCache class. This basically involved some nice access methods around a dictionary of BitmapSource objects. The dictionary key was always the unique ID for a row in the data table. I would load images into the cache when their related Image elements were realized and would continue to access those images from the cache as long as I was in the same "data scope" (i.e., while I was accessing the same data table).

Whenever I left a "data scope" (i.e., when I reloaded the data table), I simply cleared the image cache.

I also put some debug code in place to keep a collection of weak references for every BitmapSource created. (This was really easy since all image access was now through the cache.) This allowed me to track which images were not being garbage collected. I noticed that some of the roots went through the actual Image elements, so one of the changes I implemented was to always set the Source property on Image elements to null prior to those elements going out of scope. This seemed to do the trick as far as releasing the majority of the image memory (although I'm certain the Image elements themselves were still rooted... I put other changes in place to ensure those other resources would be collectable).

Anyways, hope this helps in some way.






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

cgraus

Thanks - I do the set to null thing on all references to images I don't use anymore, but I'll look over this again tonight when I am focused on it again.




Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

cgraus

I did some more research. It seems my issue is this. When I load an image, I use a BitmapImage and set it's streamsource. I then build a TransformedBitmap from that image. It seems I have two problems

1 - the transformedbitmap holds my full size bitmap in memory ( negating a whole lot of work I did ) and

2 - that stream leaks unless I keep track of it and release it when I stop using the image anywhere

Do you have any insight into this






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

-JM-

I too had to scale incoming images and instead of using TransformedBitmap, just use the original bitmap, but before setting its source, set its DecodePixelWidth (or height)

myBitmapImage.DecodePixelWidth = 200;

see the following sample:

http://msdn2.microsoft.com/en-us/library/ms743719.aspx

-Jeff





Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

cgraus

Thanks, I should have mentioned, I was doing this first, that's how I discovered that this approach totally destroys some images at certain resolutions. I sent someone at MS a project to reproduce the bug, and they have confirmed it, but no fix at this point.






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

Mike Brown

Christian,

Did our discussion this morning address your issues






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

cgraus

Hi Mike

Yes, finding out that the TransformedBItmap class is holdng on to the full sized image, and also that I need to keep track of the streams that are used to build the images, was a revelation that is going to solve a lot of my issues, I believe. I need to put some time into implimenting those changes ( this project is my night job, so I am not working on it right now ), but I did some code as we chatted, and i am certain that you've nailed my main issue. The only other thing I want to try and do now, is to take BitmapSource objects I have in memory and compress them when they are not being viewed on an Image tag, do you have any suggestons how to best go about that. Our images have labels and I've found the only way to show them exactly right is to build a second bitmap, with labels on it. This means I have two bitmaps for each Image control and I switch between them. I'd like to lower the memory footprint of the images not being shown, if I can.






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

Dr. WPF

Sounds like you have things well in hand with Mike's help. Smile

One additional optimization you might try is to cache the BitmapImage on load and then immediately dump the StreamSource:

bi = new BitmapImage();

bi.BeginInit();

bi.StreamSource = new MemoryStream(fileBuffer);

bi.CacheOption = BitmapCacheOption.OnLoad;

bi.EndInit();

bi.StreamSource.Close();

bi.StreamSource = null;

This should make an immediate sizable difference. I don't believe anything ever touches the StreamSource once the image is cached. I use this approach in my application, but I'm not constantly using the image to create transformed images the way you are. Still, I think it should work.

As for storing an object compressed, I typically use the DeflateStream() class (in System.IO.Compression) but this requires that you are able to serialize the object to a memory stream first. Not sure how this would work with your scenario since you already have a BitmapImage. You'd probably have to use a bitmap encoder to save it to a memory stream as a jpg or some such format and then use DeflateStream() on the stream. I'd be interested in hearing what kind of perf you see when swapping the images if you try such an approach. It's all in-memory work, so it shouldn't be too bad.






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

Mike Brown

Dr. WPF wrote:

Sounds like you have things well in hand with Mike's help. Smile

Yes I finally got an answer before Dr. Know-it-all WPF got to it.

Dr. WPF wrote:

One additional optimization you might try is to cache the BitmapImage on load and then immediately dump the StreamSource:

bi = new BitmapImage();

bi.BeginInit();

bi.StreamSource = new MemoryStream(fileBuffer);

bi.CacheOption = BitmapCacheOption.OnLoad;

bi.EndInit();

bi.StreamSource.Close();

bi.StreamSource = null;

This should make an immediate sizable difference. I don't believe anything ever touches the StreamSource once the image is cached. I use this approach in my application, but I'm not constantly using the image to create transformed images the way you are. Still, I think it should work.

D'oh I didn't even think about the CacheOption. Oh well can't think of everything...wait you just did

Dr. WPF wrote:

As for storing an object compressed, I typically use the DeflateStream() class (in System.IO.Compression) but this requires that you are able to serialize the object to a memory stream first. Not sure how this would work with your scenario since you already have a BitmapImage. You'd probably have to use a bitmap encoder to save it to a memory stream as a jpg or some such format and then use DeflateStream() on the stream. I'd be interested in hearing what kind of perf you see when swapping the images if you try such an approach. It's all in-memory work, so it shouldn't be too bad.

I was thinking of putting a service that could load the image from storage, downsize it to a thumbnail using GDI (yeah I know how archaic), and use that for the BitmapImage stream source. The full size images have a VERY high resolution so loading a large number of them would eat a lot of memory.

But the big issue is the memory leak caused by not being mindful of the streams. We all know what happens when they get crossed.






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

Dr. WPF

Mike Brown wrote:

Yes I finally got an answer before Dr. Know-it-all WPF got to it.

Dr. Know's Non sequitur response:

You know Mike, if you ever decided to give out awards... you could call them "Brownies". You could even give out little badges that people could display on their websites. Just thinkin' out loud here...






Re: Windows Presentation Foundation (WPF) Memory management ( second ask )

Mike Brown

Dr. WPF wrote:
Mike Brown wrote:

Yes I finally got an answer before Dr. Know-it-all WPF got to it.

Dr. Know's Non sequitur response:

You know Mike, if you ever decided to give out awards... you could call them "Brownies". You could even give out little badges that people could display on their websites. Just thinkin' out loud here...

Brownies, eh. I like that idea. And I'll have the cookie as an alternate. (Wow you figured out how to do something that twenty people have written about before you and a simple google search would find. Want a cookie ) Of course I would use those in only extreme circumstances...everyone's still learning WPF. Except of course for those of us who had an alien laser beam imprint the entire sdk on our brains.