Memory Leak Using Custom Bitmap w/ Image in WPF

Feb 10, 2011 at 4:25 PM

From the profile data I have, it appears that the System.Windows.Controls.Image class is holding on to image byte[] arrays even after I assign a different Image.Source.  Am I using Image properly?

        private void button1_Click(object sender, RoutedEventArgs e)
        {

            myIrIm = new SOPM.Imaging.Gray16SOPM(@"c:\Imagery Dataset\tau640_11-08-10_230337.ADF");

            myIrIm.LoadFrame(imageCount);
            
            image1.Source = myIrIm;
            
            ++imageCount;
        }
I can't find any examples on how to change the Image.Source (or to make the image displayed change) without creating a new instance of a CustomBitmap child class.  The problem appears to be that the Image control never releases ANY reference set to Image.Source.

The source file is actually multiple frames and I am trying to create what is, essentially, a movie player for a custom format.

Coordinator
Feb 10, 2011 at 5:18 PM
Edited Feb 26, 2011 at 1:21 AM

This doesn’t sound familiar. Please investigate a little further with a managed memory profiler to confirm the chain of references keeping the byte[] alive.

 

If you don’t have a memory profiler, CLRProfiler is a free one:

http://blogs.msdn.com/b/davbr/archive/2011/02/01/clrprofiler-v4-released.aspx

 

Feb 10, 2011 at 5:52 PM
Edited Feb 10, 2011 at 6:02 PM

First off, thanks for the quick reply!

I have checked with a profiler: JetBrains dotTrace memory profiler. Even implementing IDisposable and disposing each of my CustomBitmapSource objects, they still remain on the heap. They show up under the "Garbage Collector Handle" , but they don't ever seem to be collected, so I may have been mistaken when I said the Image control was holding the references. If I could make the Image control update/refresh itself on the screen I wouldn't have to make a new object every time... I guess I could make some sort of factory object that contains the CustomBitmapSource sub-type and have it handle the file stream and buffer byte[] so that those would be re-used for each new BmpSource object created by the factory, but I would like to understand why these objects aren't being collected in the first place so I can effectively work around or fix the root problem.

BTW, thanks for the MS profiler, I tried to find this but could only fins the .NET v2.0 one, which won't work on .NFW v4.0 code. Neither one seems to know the app has started...

Joshua A. Sells
Computer Engineer

Feb 10, 2011 at 6:04 PM

Just speculating: could the unsafe blocks be affecting the GC's collection algorithm?  I have known about unsafe blocks, in concept, but have little experience actually using them so I'm not sure of the potential pitfalls that may be in that realm.

Coordinator
Feb 11, 2011 at 6:06 AM
Edited Feb 26, 2011 at 1:21 AM

Do use GCHandle.Alloc? That would create a GC handle that might get pinned in memory. Any pointers used within unsafe blocks would, I think, get unpinned at the end of the block. But it might be worth experimenting with.

Feb 14, 2011 at 1:51 PM
I do use a GCHandle.Alloc call within my derived CustomBitmap class.  I followed the pattern you used in CustomBitmap with a try...catch...finally to make sure that GChandle.Free() is always called.  As I stated, from my profiler, I do believe that the GC owns the memory that is "leaking" but never releases it.  I am working the factory patern impl now.  I will post the results of that effort.
DwayneNeed wrote:

Do use GCHandle.Alloc? That would create a GC handle that might get pinned in memory. Any pointers used within unsafe blocks would, I think, get unpinned at the end of the block. But it might be worth experimenting with.

 

From: JASells [email removed]
Sent: Thursday, February 10, 2011 11:05 AM
To: Dwayne Need
Subject: Re: Memory Leak Using Custom Bitmap w/ Image in WPF [MicrosoftDwayneNeed:245478]

 

From: JASells

Just speculating: could the unsafe blocks be affecting the GC's collection algorithm? I have known about unsafe blocks, in concept, but have little experience actually using them so I'm not sure of the potential pitfalls that may be in that realm.

 

Feb 14, 2011 at 9:49 PM
Edited Feb 17, 2011 at 11:50 AM

 The factory pattern/re-using the byte[] memory buffer(s) did not help the leak.  I tried to find a way to make sure the pointers are reclaimed, but the only pointers I am using in my unsafe block are pointers to managed memory that has already been pinned.   Looking at the memory usage via the profiler, there is only ~10MB being used, but according to taskman, I am over 200.  The leak must be in unmanaged memory somewhere, I suspect the Image control.  Have you ever streamed 100's of images into this control?  Is it designed for this?  I can upload a simplified example, if anyone wants to see exactly what I'm doing.

Coordinator
Feb 14, 2011 at 11:22 PM
Edited Feb 26, 2011 at 1:21 AM

A simplified repro would be great. Perhaps you should use the connect site for this, as you can attach repros. We will pick it up when it gets synchronized with our internal bug system.

Feb 15, 2011 at 12:56 PM
Where/what is the connect site? Do you have a Url? I could use my skydrive storage too. 

DwayneNeed wrote:

A simplified repro would be great. Perhaps you should use the connect site for this, as you can attach repros. We will pick it up when it gets synchronized with our internal bug system.

 

From: JASells [email removed]
Sent: Monday, February 14, 2011 2:50 PM
To: Dwayne Need
Subject: Re: Memory Leak Using Custom Bitmap w/ Image in WPF [MicrosoftDwayneNeed:245478]

 

From: JASells

The factory pattern/re-using the byte[] memory buffer did not help the leak. I tried to find a way to make sure the pointers are reclaimed, but the only pointers I am using in my unsafe block are pointers to manage memory that has been pinned. Looking at the memory usage via the profiler, there is only ~10MB being used, but according to taskman, I am over 200. The leak must be in unmanaged memory somewhere, I suspect the Image control. Have you ever streamed 100's of images into this control? Is it designed for this? I can upload a simplified example, if anyone wants to see exactly what I'm doing.

 

 

Coordinator
Feb 15, 2011 at 2:37 PM
Edited Feb 26, 2011 at 1:22 AM

I was referring to http://connect.microsoft.com/WPF

 

However, if you can put your repro up on skydrive, that would work just as well.

 

 

 

Feb 17, 2011 at 11:49 AM
Edited Feb 17, 2011 at 2:02 PM

Ok, I uploaded the code with about 10 frames of the sample imagery.  http://cid-255987229e4d13e3.skydrive.live.com/redir.aspx?resid=255987229E4D13E3!134  That should be enough to easily see the memory leak, but you can loop through those 10 frames if you want to push the memory use even higher.  Data is Rgba, with alpha unused.  Code comments explain.

 

P.S.  The data file path is hard coded in the application project, so you'll have to change that to reflect your local system.

http://cid-255987229e4d13e3.skydrive.live.com/redir.aspx?resid=255987229E4D13E3!134
Feb 22, 2011 at 2:34 PM

I am just checking to see if anyone has had a chance to take a look at the code I posted.

Coordinator
Feb 25, 2011 at 1:04 AM
Edited Feb 26, 2011 at 1:22 AM

Looks like the solution is missing the WpfImageMemLeakDemo\SOPM\SOPM.Imaging\SOPM.Imaging.csproj project?

 

 

Feb 25, 2011 at 1:25 PM
So it is.   Here is a link to the missing project.  http://cid-255987229e4d13e3.office.live.com/self.aspx/.Documents/CustomBitmapMemleakExample.zip  Tonight I will put them into one download and fix previous posts' links.
DwayneNeed wrote:

Looks like the solution is missing the WpfImageMemLeakDemo\SOPM\SOPM.Imaging\SOPM.Imaging.csproj project?

 

Dwayne Need | WPF is hiring

 

From: JASells [email removed]
Sent: Tuesday, February 22, 2011 7:35 AM
To: Dwayne Need
Subject: Re: Memory Leak Using Custom Bitmap w/ Image in WPF [MicrosoftDwayneNeed:245478]

 

From: JASells

I am just checking to see if anyone has had a chance to take a look at the code I posted.

 

http://cid-255987229e4d13e3.office.live.com/self.aspx/.Documents/CustomBitmapMemleakExample.zip
Feb 25, 2011 at 1:29 PM
Btw, your hiring link is broken...
DwayneNeed wrote:

Looks like the solution is missing the WpfImageMemLeakDemo\SOPM\SOPM.Imaging\SOPM.Imaging.csproj project?

 

Dwayne Need | WPF is hiring

 

From: JASells [email removed]
Sent: Tuesday, February 22, 2011 7:35 AM
To: Dwayne Need
Subject: Re: Memory Leak Using Custom Bitmap w/ Image in WPF [MicrosoftDwayneNeed:245478]

 

From: JASells

I am just checking to see if anyone has had a chance to take a look at the code I posted.

 

Coordinator
Feb 26, 2011 at 1:20 AM
Edited Feb 26, 2011 at 1:22 AM

Your issue has been reported before:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/2113b16e-d4a2-4423-a7ae-6f386ae2706a

 

The underlying IWICBitmapSource is not being released. The above thread suggests a workaround, which is to use reflection to manually release this interface. I implemented the suggestion in your code in the CustomBitmapStream.Dispose(bool) method:

 

protected virtual void Dispose(bool disposing)

{

if (myFs != null)

myFs.Close();

 

myFs = null;

 

var field = GetType().GetField("_wicSource", BindingFlags.Instance | BindingFlags.NonPublic);

var val = (SafeHandle)field.GetValue(this);

val.Close();

 

RawFrameCache = null;

}

 

 

This solves the memory leak. However, I notice that after 10 button clicks or so, the image goes black. This happens before my change as well.

 

 

 

 
Feb 26, 2011 at 1:27 AM
There are only 10 frames in the file, so probably no data. Good to know that there is a work around. I did not find that report. Thanks for the info!

Joshua A. Sells
5400 Fowler Rd.
AMSRD-AMR-WD-UC
Office: 256.842.6925 DSN: 788.6925
Mobile: 256.503.9247


From: DwayneNeed [email removed]
Sent: Friday, February 25, 2011 08:20 PM
To: Sells, Joshua A AMRDEC
Subject: Re: Memory Leak Using Custom Bitmap w/ Image in WPF [MicrosoftDwayneNeed:245478]

From: DwayneNeed

Your issue has been reported before:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/2113b16e-d4a2-4423-a7ae-6f386ae2706a

The underlying IWICBitmapSource is not being released. The above thread suggests a workaround, which is to use reflection to manually release this interface. I implemented the suggestion in your code in the CustomBitmapStream.Dispose(bool) method:

protected virtual void Dispose(bool disposing)

{

if (myFs != null)

myFs.Close();

myFs = null;

var field = GetType().GetField("_wicSource", BindingFlags.Instance | BindingFlags.NonPublic);

var val = (SafeHandle)field.GetValue(this);

val.Close();

RawFrameCache = null;

}

This solves the memory leak. However, I notice that after 10 button clicks or so, the image goes black. This happens before my change as well.

From: JASells [email removed]
Sent: Friday, February 25, 2011 6:30 AM
To: Dwayne Need
Subject: Re: Memory Leak Using Custom Bitmap w/ Image in WPF [MicrosoftDwayneNeed:245478]

From: JASells

Btw, your hiring link is broken...

DwayneNeed wrote:

Looks like the solution is missing the WpfImageMemLeakDemo\SOPM\SOPM.Imaging\SOPM.Imaging.csproj project?

Dwayne Need | WPF is hiring

From: JASells [email removed]
Sent: Tuesday, February 22, 2011 7:35 AM
To: Dwayne Need
Subject: Re: Memory Leak Using Custom Bitmap w/ Image in WPF [MicrosoftDwayneNeed:245478]

From: JASells

I am just checking to see if anyone has had a chance to take a look at the code I posted.

Aug 14, 2014 at 2:54 PM
I know that this entry is quite old, but I just stumbled upon it and noticed that this behaviour changed from .NET 4.0 to .NET 4.5. The latter does no longer produce memory leaks.

The root cause for the memory leak is the internal ManagedBitmapSource class which is reference counted (COM) and used by the BitmapSource class. This is what the _wicSource handle points to. The ManagedBitmapSource has a reference to the original BitmapSource class, thus creating a cycle which the GC cannot break.

In .NET 4.5 the cycle is broken by making the reference from ManagedBitmapSource to the original BitmapSource a WeakReference.

For this reason the workarround described above is no longer needed from .NET 4.5 on forward.