none
RenderTargetBitmap() Out of Memory Exception

    質問

  • Hi All,

    I am using RenderTargetBitmap() function in a loop. I am facing out of memory exception when I execute the function. Below is the function which I use.

    Out Of memory exception

    Any help will be highly appreciated...

    Thanks,

    Ajit

    2013年6月17日 7:21

回答

  • "How can I compress image?"

    Well, you're already compressing it using PNG. If PNG doesn't compress well enough and you can afford quality loss then try using JPEG.

    "what do you mean by use temporary file instead of memoryStream?"

    Something like:

                string tempFilePath = System.IO.Path.GetTempFileName();
    
                using (var stream = File.OpenWrite(tempFilePath))
                    encoder.Save(stream);
    
                return System.Drawing.Image.FromFile(tempFilePath);
    

    You'll have to keep track of the temp file and delete it after you dispose the image.

    "yes, I  am generating more than 300 files, so when i can dispose it, can I use finally block to clear the resources?"

    Well, you probably should a finally block somewhere. When/where? I don't know, depends what you are doing with those images. Why do you need to convert WPF images to System.Drawing images anyway?

    2013年6月17日 9:16
    モデレータ
  • Well, that pretty much means that you don't have enough memory for what you are trying to do. Think about it, you need 200 megabytes for the render target and another 200 megabytes for the image. Depending on the how well the image compresses you also need who knows how many megabytes for the memory stream.

    There aren't many options here:

    • switch to 64 bit
    • decrease the image resolution

    Make sure the images you are creating are disposed, you haven't confirmed that you did that. As a hackish workaround try adding a GC.Collect before Image.FromStream.

    2013年6月19日 10:04
    モデレータ

すべての返信

  • How large is that RenderTargetBitmap? From your contract code it looks like it can be as big as 7000x7000. That will require tons of memory so it's not very surprising that you run into out of memory exceptions.

    Also, what version of .NET are you using? I did a test with code like yours and .NET 4.5 seems to work better than 3.5 in this case. 3.5 appears to leak memory or something...

    2013年6月17日 7:57
    モデレータ
  • Hi Mike,

    Thanks for the reply. Yes, you are right,  the image size is 7000x7000. 

    I running this application on .Net 4.0. Frameowork. I think in .NET 4.0 memory leak is till there...

    How can I solve this issue?

    -Ajit


    2013年6月17日 8:39
  • Well, I tested on .NET 4 too and such code works fine. I can see only 2 reasons to get out of memory exceptions:

    • Whatever your are drawing on that image doesn't compress well and the size of the resulting png is large - consider using a temporary file instead of a MemoryStream
    • You're generating multiple such images and you keep them all in memory. Make sure you call dispose on the resulting image as soon as you no longer need it.
    2013年6月17日 8:56
    モデレータ
  • Hi Mike,

    • Whatever your are drawing on that image doesn't compress well and the size of the resulting png is large - consider using a temporary file instead of a MemoryStream

    => How can I compress image? what do you mean by use temporary file instead of memoryStream?

    • You're generating multiple such images and you keep them all in memory. Make sure you call dispose on the resulting image as soon as you no longer need it.

    => yes, I  am generating more than 300 files, so when i can dispose it, can I use finally block to clear the resources?

    Ca you please send me code for that?

    -Ajit


    2013年6月17日 9:00
  • "How can I compress image?"

    Well, you're already compressing it using PNG. If PNG doesn't compress well enough and you can afford quality loss then try using JPEG.

    "what do you mean by use temporary file instead of memoryStream?"

    Something like:

                string tempFilePath = System.IO.Path.GetTempFileName();
    
                using (var stream = File.OpenWrite(tempFilePath))
                    encoder.Save(stream);
    
                return System.Drawing.Image.FromFile(tempFilePath);
    

    You'll have to keep track of the temp file and delete it after you dispose the image.

    "yes, I  am generating more than 300 files, so when i can dispose it, can I use finally block to clear the resources?"

    Well, you probably should a finally block somewhere. When/where? I don't know, depends what you are doing with those images. Why do you need to convert WPF images to System.Drawing images anyway?

    2013年6月17日 9:16
    モデレータ
  • Hi Mike,

    we can not use JPEG format :(. Also can not use temp. files due to some third party restrictions :(

    Let me check other possibilities to Dispose the images.

    -Ajit

    2013年6月17日 10:07
  • Hi Mike,

    Now calling above function is Using block so it will take care of GC.

    See below code:

          using (MemoryStream stream = new MemoryStream())
                {
                    encoder.Save(stream);
                    stream.Position = 0;
                    image = Image.FromStream(stream); //Gives OOM
                }

    I dont know why it is going OOM, and what can i do to avoid that.

    -Ajit

    2013年6月19日 8:54
  • "Now calling above function is Using block so it will take care of GC."

    The "using" present in your code has nothing to do with GC or the OOM. Tipically using releases unmanaged resources but MemoryStream doesn't use any unmanaged resources.

    "I dont know why it is going OOM"

    Well, Image.FromStream sometimes throws OOM for unrelated reasons (tipically with corrupted images) but I doubt that's the case here. Is that the only line where you get OOM? I would expect "new RenderTargetBitmap(..." to cause problems too.

    2013年6月19日 9:26
    モデレータ
  • Previously the crash was with RenderTargetBitmap but now I can see the crash in happening at  Image.FromStream(stream);

    -Ajit

    2013年6月19日 9:50
  • Well, that pretty much means that you don't have enough memory for what you are trying to do. Think about it, you need 200 megabytes for the render target and another 200 megabytes for the image. Depending on the how well the image compresses you also need who knows how many megabytes for the memory stream.

    There aren't many options here:

    • switch to 64 bit
    • decrease the image resolution

    Make sure the images you are creating are disposed, you haven't confirmed that you did that. As a hackish workaround try adding a GC.Collect before Image.FromStream.

    2013年6月19日 10:04
    モデレータ