WPF memory leak BitmapImage
-
As previously suggested, check the .NET versions on the machines; there have been a few issues that vary by version. I would probably try moving the creation of the BitmapImage outside of the `using` block, or try some garbage collection routines, or object disposal to see what kind of response you get from what methods
Director of Transmogrification Services Shinobi of Query Language Master of Yoda Conditional
Oh, I was hoping .Net would be solid. How on earth do we ensure that customers have a bug free version, if that is the cause?
-
Thanks for spotting that, it actually isn't missing in our code, but it is missing from the sample I pasted here. Ooops. Sorry about that.
-
Oh, I was hoping .Net would be solid. How on earth do we ensure that customers have a bug free version, if that is the cause?
-
Then maybe you're also running "different" versions of the app ... (I like to put the version # in the title bar).
"(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal
No, just stupidity on my part when copying code to this forum.
-
First you must ensure that your code in itself is bug free.
Director of Transmogrification Services Shinobi of Query Language Master of Yoda Conditional
MadMyche wrote:
First you must ensure that your code in itself is bug free.
If I simply discard the BitmapImage created by the quoted code, rather than saving it, the memory leak is present.
-
We have some code which receives images of a document from a C++ DLL, and displays them in a WPF application. The C# code stores the images in an array, which it flushes each time a new document is placed on the scanner. The code converts the image from a Bitmap to a BitmapImage, which is the image type for display in WPF:
private BitmapImage CreateBitmapImage(Bitmap bitmap) { using (MemoryStream memory = new MemoryStream()) { bitmap.Save(memory, ImageFormat.Bmp); memory.Position = 0; BitmapImage bitmapimage = new BitmapImage(); bitmapimage.BeginInit(); bitmapimage.StreamSource = memory; bitmapimage.CacheOption = BitmapCacheOption.OnLoad; bitmapimage.EndInit(); bitmapimage.Freeze(); return bitmapimage; } }
The above code leaks, but only on some PCs. On most it is okay. It can be fine on one Windows 10 PC, and leak on another that has Windows 10 on the same hardware. A key point to note is that the DLL module is also passing the bitmap handle to a third party validation DLL, and if we remove that DLL, the memory leak disappears. If I remove the Freeze() call, the code does not leak, but the images are not displayed. If I comment out the return call, and return null instead, the code still leaks. Therefore the issue is not that we do not clear the stored images. That this only occurs on some PCs, might suggest a timing issue associated with the validation DLL. Thoughts? :) Note: Edited to correct the code. For some reason I'd copied it with a key line missing!
I have 'solved' the memory leak in our products but I don't understand why. This is a snippet of the code: MemoryStream memoryStream = (_bitmapImages[index] != null) ? (_bitmapImages[index].StreamSource as MemoryStream): new MemoryStream(); _bitmapImages[index] = CreateBitmapImage(bitmap, memoryStream); The modified CreateBitmapImage method takes a MemoryStream instance as an argument. We retain our images for a short time, and then clear them. If a new image arrives before the previous one has been cleared, we reuse the MemoryStream from the old one. Note that the above ignores issues with threading and serialising access to the _bitmapImages[index] value, as I wanted to keep the snippet simple. This solves our memory leak, but not understanding why is concerning.
-
We have some code which receives images of a document from a C++ DLL, and displays them in a WPF application. The C# code stores the images in an array, which it flushes each time a new document is placed on the scanner. The code converts the image from a Bitmap to a BitmapImage, which is the image type for display in WPF:
private BitmapImage CreateBitmapImage(Bitmap bitmap) { using (MemoryStream memory = new MemoryStream()) { bitmap.Save(memory, ImageFormat.Bmp); memory.Position = 0; BitmapImage bitmapimage = new BitmapImage(); bitmapimage.BeginInit(); bitmapimage.StreamSource = memory; bitmapimage.CacheOption = BitmapCacheOption.OnLoad; bitmapimage.EndInit(); bitmapimage.Freeze(); return bitmapimage; } }
The above code leaks, but only on some PCs. On most it is okay. It can be fine on one Windows 10 PC, and leak on another that has Windows 10 on the same hardware. A key point to note is that the DLL module is also passing the bitmap handle to a third party validation DLL, and if we remove that DLL, the memory leak disappears. If I remove the Freeze() call, the code does not leak, but the images are not displayed. If I comment out the return call, and return null instead, the code still leaks. Therefore the issue is not that we do not clear the stored images. That this only occurs on some PCs, might suggest a timing issue associated with the validation DLL. Thoughts? :) Note: Edited to correct the code. For some reason I'd copied it with a key line missing!
Thanks to everyone who replied. I believe that I have solved this. The code behaves as if the MemoryStream Dispose method is never called. So the obvious fix is to explicitly dispose of the stream:
void ClearBitmapImage(int type) { if (\_myBitmapImages\[type\] != null) { System.IO.Stream stream = \_myBitmapImages\[type\].Bitmap.StreamSource; \_myBitmapImages\[type\].Bitmap = null; stream.Dispose(); \_myBitmapImages\[type\] = null; } }
The Bitmap property is an instance of BitmapImage. I also do a collect as otherwise it takes an age to clean up the memory:
GC.Collect(); GC.WaitForPendingFinalizers();
I still do not understand why we do not see this unless we are using a third party validation DLL!
-
We have some code which receives images of a document from a C++ DLL, and displays them in a WPF application. The C# code stores the images in an array, which it flushes each time a new document is placed on the scanner. The code converts the image from a Bitmap to a BitmapImage, which is the image type for display in WPF:
private BitmapImage CreateBitmapImage(Bitmap bitmap) { using (MemoryStream memory = new MemoryStream()) { bitmap.Save(memory, ImageFormat.Bmp); memory.Position = 0; BitmapImage bitmapimage = new BitmapImage(); bitmapimage.BeginInit(); bitmapimage.StreamSource = memory; bitmapimage.CacheOption = BitmapCacheOption.OnLoad; bitmapimage.EndInit(); bitmapimage.Freeze(); return bitmapimage; } }
The above code leaks, but only on some PCs. On most it is okay. It can be fine on one Windows 10 PC, and leak on another that has Windows 10 on the same hardware. A key point to note is that the DLL module is also passing the bitmap handle to a third party validation DLL, and if we remove that DLL, the memory leak disappears. If I remove the Freeze() call, the code does not leak, but the images are not displayed. If I comment out the return call, and return null instead, the code still leaks. Therefore the issue is not that we do not clear the stored images. That this only occurs on some PCs, might suggest a timing issue associated with the validation DLL. Thoughts? :) Note: Edited to correct the code. For some reason I'd copied it with a key line missing!
I've come across the source for one version of MemoryStream: Reference Source[^] The interesting feature here is that the Dispose method does NOT set the buffer reference to null. That seems a bizarre choice.
-
We have some code which receives images of a document from a C++ DLL, and displays them in a WPF application. The C# code stores the images in an array, which it flushes each time a new document is placed on the scanner. The code converts the image from a Bitmap to a BitmapImage, which is the image type for display in WPF:
private BitmapImage CreateBitmapImage(Bitmap bitmap) { using (MemoryStream memory = new MemoryStream()) { bitmap.Save(memory, ImageFormat.Bmp); memory.Position = 0; BitmapImage bitmapimage = new BitmapImage(); bitmapimage.BeginInit(); bitmapimage.StreamSource = memory; bitmapimage.CacheOption = BitmapCacheOption.OnLoad; bitmapimage.EndInit(); bitmapimage.Freeze(); return bitmapimage; } }
The above code leaks, but only on some PCs. On most it is okay. It can be fine on one Windows 10 PC, and leak on another that has Windows 10 on the same hardware. A key point to note is that the DLL module is also passing the bitmap handle to a third party validation DLL, and if we remove that DLL, the memory leak disappears. If I remove the Freeze() call, the code does not leak, but the images are not displayed. If I comment out the return call, and return null instead, the code still leaks. Therefore the issue is not that we do not clear the stored images. That this only occurs on some PCs, might suggest a timing issue associated with the validation DLL. Thoughts? :) Note: Edited to correct the code. For some reason I'd copied it with a key line missing!
I've come across the source for MemoryStream which shows that the Dispose method does NOT set the buffer reference to null. And I can work around the memory leak by assigning a persistent buffer to the MemoryStream instance instead of allowing it to allocate its own buffer. I still don't fully understand what is happening. :(
-
We have some code which receives images of a document from a C++ DLL, and displays them in a WPF application. The C# code stores the images in an array, which it flushes each time a new document is placed on the scanner. The code converts the image from a Bitmap to a BitmapImage, which is the image type for display in WPF:
private BitmapImage CreateBitmapImage(Bitmap bitmap) { using (MemoryStream memory = new MemoryStream()) { bitmap.Save(memory, ImageFormat.Bmp); memory.Position = 0; BitmapImage bitmapimage = new BitmapImage(); bitmapimage.BeginInit(); bitmapimage.StreamSource = memory; bitmapimage.CacheOption = BitmapCacheOption.OnLoad; bitmapimage.EndInit(); bitmapimage.Freeze(); return bitmapimage; } }
The above code leaks, but only on some PCs. On most it is okay. It can be fine on one Windows 10 PC, and leak on another that has Windows 10 on the same hardware. A key point to note is that the DLL module is also passing the bitmap handle to a third party validation DLL, and if we remove that DLL, the memory leak disappears. If I remove the Freeze() call, the code does not leak, but the images are not displayed. If I comment out the return call, and return null instead, the code still leaks. Therefore the issue is not that we do not clear the stored images. That this only occurs on some PCs, might suggest a timing issue associated with the validation DLL. Thoughts? :) Note: Edited to correct the code. For some reason I'd copied it with a key line missing!
Thank you to everyone for your thoughts. It appears to be unrelated to the version of .Net. I found the source for MemoryStream and the Dispose method does NOT set the buffer reference to null. I tried assigning a static buffer to the MemoryStream instance instead of allowing it to allocate its own buffer but that caused a crash. I created test WPF and WinForms apps and the results are bizarre. We have a small C# class - VideoOCRWrapper - which drives an attached OCR document scanner. It essentially makes calls to a C++ DLL, and has a callback which receives a IntPtr containing a HWND. On receipt of a bitmap, it converts it to a BitmapImage and fires an event to provide a client with the BitmapImage isntance. I created a WinForms app, which initialises VideoOCRWrapper and displays the received bitmap. It has converts the BitmapImage to a Bitmap for display.It shows no memory leaks. I created a WPF app, which initialises VideoOCRWrapper and displays the received bitmap. It shows a huge memory leak consistent with the bitmap buffer leaking. The two apps use almost the same code, except that the WinForms overrides the form's WndProc, whereas the WPF app hooks its own WndProc onto the main window. I memory profiled the WPF test app, and it said that "22 types have instances that are queued for finalization. This can indicate that a Finalizer method is stuck, which will prevent instances from being finalized and cause memory leaks.". There is an extra factor. We use a third party DLL for document verification, which receives bitmaps from us. If I remove that DLL, our code shows no leaks. If I add that DLL, we have leaks but only when running our WPF test app, or our WPF application. When running the WinForms test app, we have no leaks.