views:

576

answers:

2

I'm developing an application that uses a mobile device to take a photo and send it using a webservice. But after I've taken 4 photos I am getting an OutOfMemoryException in the code below. I tried calling GC.Collect() but it didn't help either. Maybe someone here could be give me an advice how to handle this problem.

public static Bitmap TakePicture()
{
    var dialog = new CameraCaptureDialog
    {
        Resolution = new Size(1600, 1200),
        StillQuality = CameraCaptureStillQuality.Default
    };

    dialog.ShowDialog();

    // If the filename is empty the user took no picture
    if (string.IsNullOrEmpty(dialog.FileName))
       return null;

    // (!) The OutOfMemoryException is thrown here (!)
    var bitmap = new Bitmap(dialog.FileName);

    File.Delete(dialog.FileName);

    return bitmap;
}

The function is called by an event handler:

private void _pictureBox_Click(object sender, EventArgs e)
{
    _takePictureLinkLabel.Visible = false;

    var image = Camera.TakePicture();
    if (image == null)
       return;

    image = Camera.CutBitmap(image, 2.5);
    _pictureBox.Image = image;

    _image = Camera.ImageToByteArray(image);
}
+2  A: 

Your mobile device usually does not have any memory swapping to disk option, so since you choose to store your images as bitmaps in memory rather than files on disk, you quickly consume your phone's memory. Your "new Bitmap()" line allocates a large chunk of memory, so it is very likely to throw the exception there. Another contender is your Camera.ImageToByteArray that will allocate a large amount of memory. This probably isn't large to what you're used to with your computer, but for your mobile this is gigantic

Try keeping the pictures on disk until you use them, i.e. until sending them to the webservice. For displaying them, use your built-in controls, they are probably the most memory efficient and you can usually point them to the image files.

Cheers

Nik

niklassaers-vc
There's no "usually" to it. CE does not have any provision to swap to disk at all, so no device does it.
ctacke
+4  A: 

I suspect you are holding onto references. As a minor cause, note that dialogs don't dispose themselves when using ShowDialog, so you should be using the dialog (although I would expect GC to still collect an undisposed but non-referenced dialog).

Likewise, you should probably be using the image, but again: not sure I'd expect this to make-or-break; worth a try, though...

public static Bitmap TakePicture()
{
    string filename;
    using(var dialog = new CameraCaptureDialog
    {
        Resolution = new Size(1600, 1200),
        StillQuality = CameraCaptureStillQuality.Default
    }) {

        dialog.ShowDialog();
        filename = dialog.FileName;
    }    
    // If the filename is empty the user took no picture
    if (string.IsNullOrEmpty(filename))
       return null;

    // (!) The OutOfMemoryException is thrown here (!)
    var bitmap = new Bitmap(filename);

    File.Delete(filename);

    return bitmap;
}

private void _pictureBox_Click(object sender, EventArgs e)
{
    _takePictureLinkLabel.Visible = false;

    using(var image = Camera.TakePicture()) {
        if (image == null)
           return;

        image = Camera.CutBitmap(image, 2.5);
        _pictureBox.Image = image;

        _image = Camera.ImageToByteArray(image);
    }
}

I'd also be a little cautious of the CutBitmap etc, to ensure that things are released ASAP.

Marc Gravell
I'd modify your code slightly - where it sets the picturebox image, I'd dispose of any existing image first, a la if(_pictureBox.Image != null) _pictureBox.Image.Dispose().
ctacke