4

I have a problem with a memory leak.

I have this code in a button_click :

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

    Dim ms As New IO.MemoryStream
    Dim bm As New Bitmap("\Application Data\imgs\IMG22.jpg")
    bm.Save(ms, Drawing.Imaging.ImageFormat.Jpeg)
End Sub

This code works just fine when I'm running the .exe at my laptop (I mean under windows7/32bits with the full .net framework) but when I run the app in a device with WindowsMobile 6.1 the app throws this exception:

SmartDeviceProject22.exe
OutOfMemoryException

at

Microsoft.AGL.Common.MISC.HandleAr(PAL_ERROR ar)
at
System.Drawing.Image.Save(Stream stream, ImageFormat format)
at
SmartDeviceProject22.Form1.Button3_Click(Object sender, EventArgs e)
at
....

The image size is around 200kb and the width and height around 1500px. Details of image:

  • Dimension: 1536x2048
  • Horizontal Resolution: 72dpi
  • Horizontal Resolution: 72dpi
  • Bit depth: 24
  • Resolution unit: 2
  • Color representation: sRGB -

Any help it will be really appreciated.

I try the code of @asawyer even remove ALL the code,reference, etc and the problem keeps, I guess it's something about the width/height of the image or with the compact framework.

Any other advice ?

Solution and explanation of the problem Well after test somethings the real problem it was not a memory leak, just as @pdriegen said its a problem of memory available .

I change my code to this (and tested at the mobile device):

 Dim fs As IO.FileStream = IO.File.OpenRead("\Application Data\ryder\IMG23.jpg")
 Dim arrb(fs.Length) As Byte     
 fs.Read(arrb, 0, arrb.Length)
 fs.Close()
 fs.Dispose()

And with the code above (apparently) I get a byte() (array) of the image to store in the database using dataSet.

In conclusion: load a bitmap object to memoryStream, bad idea. Many thanks to everyone who take its time to read my problem,and specially those who post their answer.

Solution (if you need to show the image in a picture box):

After a few weeks, this probably the best (for free) solution: Implement an ImageHelper as is explained here: ImageHelper

updated link to the ImageHelper https://opennetcf.com/2010/10/13/loading-parts-of-large-images-in-the-compact-framework/

This class/sample uses the Drawing NameSpace from OpenNetCF (http://www.opennetcf.com/)

It works great and it solve my memory troubles loading big bitmaps to memory, actually we load a thumbnail, so the size in memory is reduced considerably and avoid the OutOfMemory exception problem.

About Chris Tacke I just realize that the author of the post about ImageHelper and co-founder of OpenNetCF it's here at stackoverflow, here is his profile: https://stackoverflow.com/users/13154/ctacke

updated link https://opennetcf.com/2010/10/13/loading-parts-of-large-images-in-the-compact-framework/

Allende
  • 1,480
  • 2
  • 22
  • 39

2 Answers2

5

I don't believe the problem is a memory leak. Instead, the problem is a lack of available memory.

Even though the compressed image size is 200kb, when you load it as a bitmap it will be decompressed and stored in memory in native Bitmap format. Given a height and width of 1500px each, and assuming a bitmap format of 32bpp (the default when not specified), you're looking at 9MB of allocated memory

1500 * 1500 * 4 = 9MB.

Given the memory constraints present in the mobile device OS (32MB/process - space allocated by system dlls), you may well be in a memory crunch scenario. It's unknown to me of course what other memory is allocated by the application you are running this code in.

Try the same code on the same device with a smaller image. You should see that it executes fine.

pdriegen
  • 2,019
  • 1
  • 13
  • 19
  • Ohhh greate, well I read something about it here [link](http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesvbcs/thread/53905933-a731-4468-9d0e-1c0851c693c8#5d70505c-1e71-4e1a-9301-d26ab5f2abd9) Let me try with a smaller image, but then there's no way to do this, I need to pass the image to a byte array to store it a data base, actually it works on a PC (I guess cause I can abuse of the memory), but I got this problem on de mobile device. – Allende Jun 14 '12 at 16:02
  • 1
    If you just need to pass the jpeg as a byte array, why don't you just use the FileStream object to read the byte data out of the file directly rather than de-compressing to a bitmap first? – pdriegen Jun 14 '12 at 17:03
  • probably because I have no idea what I'm doing, well kind of, let me try, but in the meanwhile you were right I just tested with a 400x400 image and the exception didn't come out. – Allende Jun 14 '12 at 17:36
1

Your leaking Gdi handles, wrap the stream and bitmap in Using clauses.

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

    using ms As New IO.MemoryStream
        using bm As New Bitmap("\Application Data\imgs\IMG22.jpg")
            bm.Save(ms, Drawing.Imaging.ImageFormat.Jpeg)
        end using
    end using

End Sub
asawyer
  • 17,642
  • 8
  • 59
  • 87
  • Hi @asawyer Oamm I don't really understand you, but even wrapping the stream and bitmap (just as you show me), the app throws the same exception when it's running at the device. – Allende Jun 14 '12 at 15:09
  • @Allende pdriegen is probably correct, but this could have been contributing as well. – asawyer Jun 14 '12 at 17:00
  • Hi @asawyer, I'm sorry I didn't be rude, but then If I understood well to wrapping with "using" the objects help to free resources then, something like use .dispose() method ? Or I'm still lost ? – Allende Jun 14 '12 at 17:38
  • 1
    @Allende `using` will transform it into a try/finally block that automatically calls `Dispose()` for the object. The runtime will handle these things for you sure, but sometimes you need that resource freed asap, like in memory stressed situations. In windows streams and bitmaps allocate underlying OS objects that will not be released until the GC picks them up at some point in the future if you do not call `Dispose` on them. – asawyer Jun 14 '12 at 17:41