Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. WPF
  4. WPF memory leak BitmapImage

WPF memory leak BitmapImage

Scheduled Pinned Locked Moved WPF
csharpc++wpfgraphicshardware
17 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Leif Simon Goodwin

    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!

    L Offline
    L Offline
    Lost User
    wrote on last edited by
    #4

    Your code shows you using an "empty" stream to create an image. How is that supposed to work?

    "(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal

    1 Reply Last reply
    0
    • L Leif Simon Goodwin

      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!

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #5

      You're trying to create an image from an "empty" memory stream; key statement missing:

              bitmap.Save( memory, System.Drawing.Imaging.ImageFormat.Bmp );
      

      "(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal

      L 1 Reply Last reply
      0
      • L Lost User

        You're trying to create an image from an "empty" memory stream; key statement missing:

                bitmap.Save( memory, System.Drawing.Imaging.ImageFormat.Bmp );
        

        "(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal

        L Offline
        L Offline
        Leif Simon Goodwin
        wrote on last edited by
        #6

        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.

        L 1 Reply Last reply
        0
        • realJSOPR realJSOP

          Are all machines running exactly the same version of .Net?

          ".45 ACP - because shooting twice is just silly" - JSOP, 2010
          -----
          You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
          -----
          When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013

          L Offline
          L Offline
          Leif Simon Goodwin
          wrote on last edited by
          #7

          I will check.

          1 Reply Last reply
          0
          • M MadMyche

            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

            L Offline
            L Offline
            Leif Simon Goodwin
            wrote on last edited by
            #8

            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?

            M 1 Reply Last reply
            0
            • L Leif Simon Goodwin

              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.

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #9

              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

              L 1 Reply Last reply
              0
              • L Leif Simon Goodwin

                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?

                M Offline
                M Offline
                MadMyche
                wrote on last edited by
                #10

                First you must ensure that your code in itself is bug free.


                Director of Transmogrification Services Shinobi of Query Language Master of Yoda Conditional

                L 1 Reply Last reply
                0
                • L Lost User

                  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

                  L Offline
                  L Offline
                  Leif Simon Goodwin
                  wrote on last edited by
                  #11

                  No, just stupidity on my part when copying code to this forum.

                  1 Reply Last reply
                  0
                  • M MadMyche

                    First you must ensure that your code in itself is bug free.


                    Director of Transmogrification Services Shinobi of Query Language Master of Yoda Conditional

                    L Offline
                    L Offline
                    Leif Simon Goodwin
                    wrote on last edited by
                    #12

                    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.

                    1 Reply Last reply
                    0
                    • L Leif Simon Goodwin

                      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!

                      L Offline
                      L Offline
                      Leif Simon Goodwin
                      wrote on last edited by
                      #13

                      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.

                      1 Reply Last reply
                      0
                      • L Leif Simon Goodwin

                        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!

                        L Offline
                        L Offline
                        Leif Simon Goodwin
                        wrote on last edited by
                        #14

                        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!

                        1 Reply Last reply
                        0
                        • L Leif Simon Goodwin

                          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!

                          L Offline
                          L Offline
                          Leif Simon Goodwin
                          wrote on last edited by
                          #15

                          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.

                          1 Reply Last reply
                          0
                          • L Leif Simon Goodwin

                            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!

                            L Offline
                            L Offline
                            Leif Simon Goodwin
                            wrote on last edited by
                            #16

                            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. :(

                            1 Reply Last reply
                            0
                            • L Leif Simon Goodwin

                              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!

                              L Offline
                              L Offline
                              Leif Simon Goodwin
                              wrote on last edited by
                              #17

                              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.

                              1 Reply Last reply
                              0
                              Reply
                              • Reply as topic
                              Log in to reply
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes


                              • Login

                              • Don't have an account? Register

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • World
                              • Users
                              • Groups