Large memory usage

Feb 12, 2013 at 7:21 PM
I am presently using the WriteableBitmap.Crop extension method and then saving the results with the SaveToFile extension. This is how I am using it:

using(var stream = await _File.OpenAsync(FileAccessMode.Read))
{
WriteableBitmap wBmp = await BitmapFactory.New(1, 1).FromStream(stream);
WriteableBitmap cropped = null;

// Some logic to decide how image is to be cropped

cropped = wBmp.Crop(nChopX, nChopY, nFinalWidth, nFinalHeight);

await [extension namespace].SaveToFile(cropped, folder, strFileName);
}

For a 3MP webcam image this call causes the memory working set to grow by at least 100MB, possibly 200MB. While this could be normal, the memory allocation stays around a long time. If I call GC.Collect(), I can get it to drop. However, it is not hard for my Windows Store app to temporarily exceed a working set of 500MB which is cause for WACK failure.

In WriteableBitmapCropExtensions.cs, I can see that you use two Streams for input and output. Would it make any difference to put those inside "using" blocks so that they are Disposed at the end of the call? Although they do go out of scope, doesn't calling Dispose on IDisposable objects (whether explicitly or through a using block) tell the GC that they can be freed immediately?

I have carefully combed my code and commented out everything. Then, bringing things back in one at a time while watching memory usage, I was able to see that the crop operation is very costly.
Coordinator
Feb 12, 2013 at 8:43 PM
That could work. Let me know how this works for you. I don't think I've used the crop extensions for anything shipping, so it might not be the most stable of the tools in the belt. I've had to call GC.Collect() on many occasions before just to satisfy WACK or whatever its Windows Phone version was called. If I neglected to dispose these streams - I am sure this might help too.
Feb 12, 2013 at 8:57 PM
I copied the cropping code into my own function and then added calls Dispose() on those two streams. It did make a noticeable difference in the memory "balloon effect." However, for some reason my copy of the same code results in a different crop! I haven't figured it out yet, and am trying to find a away to simulate what I am doing within the WinRTXamlToolkit source so I can debug it.
Jan 24, 2014 at 3:24 PM
Edited Jan 24, 2014 at 3:26 PM
Hello Filip,

I am revisiting this block of code in my Instant Photo Booth app because I am getting consistent errors from users. It's been a year and the app has been through ten releases, ~12,000 downloads, and lots of in-the-field testing. I use MarkedUp analytics to capture error logs. There is a particularly frequent error with my latest release that was brought to my attention by a user.

For some reason many users, especially on Microsoft Surface RT devices (but also on others), are getting the generic exception "Error HRESULT E_FAIL has been returned from a call to a COM component" from a call to WinRTXamlToolkit.Imaging.WriteableBitmapSaveExtensions.SaveToFile. This call happens right after the cropping functions discussed earlier in this thread.

This code is essentially unchanged since the first release a year ago, but my error reporting is better. I suspect this error has occured for many other users too, but I haven't seen it until now.

Of course I can't duplicate the error here, even on a Surface RT device. After puzzling over this for quite a while I am beginning to wonder if something isn't quite ready to be saved when SaveToFile is called? There are no async calls in any of the cropping code, so I would think that nothing would happen until all the pixel manipulation is done. But maybe there is some async process outside my code that isn't ready yet?

Do you have any insights or theories? The code block above is exactly what I am doing. The only ommitted code is how to compute the input values to the Crop function.

Thank you!
Thaine