Bug 752 - Possible memory leak
Summary: Possible memory leak
Status: RESOLVED NOT_REPRODUCIBLE
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler ()
Version: 1.0
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: dean.ellis
URL:
Depends on:
Blocks:
 
Reported: 2011-09-12 02:50 UTC by Vegard Andreas Larsen
Modified: 2012-11-20 14:15 UTC (History)
5 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Example project (22.23 KB, application/octet-stream)
2011-09-12 02:50 UTC, Vegard Andreas Larsen
Details
Fixed Sample Project (25.23 KB, application/x-zip-compressed)
2012-11-20 14:15 UTC, dean.ellis
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED NOT_REPRODUCIBLE

Description Vegard Andreas Larsen 2011-09-12 02:50:49 UTC
Created attachment 325 [details]
Example project

I am still assuming this is me doing something I don't realize to be bad, but here goes anyhow.

The attached project leaks memory. It consists of a simple ViewFlipper that flips between "pages" inflated from a layout file. The pages each contain a simple "Next" Button and an ImageView. The ImageView is populated by reading the name of the file to load from a JSON file (which reflects how I originally discovered this bug), and loading the image into a Bitmap. The Bitmap is then set as the drawable for the ImageView, and Dispose()'d.

You should expect to have to click "Next" a lot before an OutOfMemoryError crashes the project.

If you watch the project using the Dalvik Debug Monitor, show heap updates for MemoryLeak.MemoryLeak, and watch the "data objects" counter increase regularly for each page view.
Comment 2 dean.ellis 2012-11-20 14:15:15 UTC
There are a few tweaks to the sample application that correct the memory leak. 

The first is changing LoadJSONFile to close and dispose of the stream it opens

public JsonValue LoadJSONFile(string filename)
        {
            using (Stream stream = Assets.Open(filename))
            {
                var value = JsonValue.Load(stream);
                stream.Close();
                return value;
            }
        }

the next set of change has to do with cleaning up some objects when a page is removed from the flipper. So we replace the current while loop with

while (flipper.ChildCount > 1)
                    {
                        var pagetoRemove = (View)flipper.GetChildAt(0);
                        if (pagetoRemove != null)
                        {
                            // remove Click Assignment 
                            var button1 = pagetoRemove.FindViewById<Button>(Resource.Id.button);
                            if (button1 != null)
                            {
                                button1.Click -= ButtonClick;
                            }
                            var image1 = pagetoRemove.FindViewById<ImageView>(Resource.Id.image);
                            if (image1 != null && image1.Drawable is BitmapDrawable)
                            {
                                // get the drawable
                                using (var d = image1.Drawable)
                                {
                                    // remove the reference the imageView has
                                    image1.SetImageBitmap(null);
                                    // recycle it
                                    ((BitmapDrawable)d).Bitmap.Recycle();
                                }                                
                            }

                        }
                        flipper.RemoveViewAt(0);
                    }

What seemed to be happening was that some objects could not be GC'd, forcing a full GC.Collect() in the button click removed the memory leak. So to "fix" the issue without using a manual call to Collect we need to clean up a few items when we remove the page. 

The first is to remove the Click event handler just to make sure that this is not stopping the button from being collected. The next is to deal with the Bitmap that was attached to the ImageView. In the fix we check if the ImageView.Drawable is set and is a BitmapDrawable, if it is we make sure we Recycle and Dispose of it. You had to call SetImageBitmpa(null) before Recycling the Bitmap otherwise you will get an exception.

I have attached a new version of the project for people to look at.
Comment 3 dean.ellis 2012-11-20 14:15:43 UTC
Created attachment 2978 [details]
Fixed Sample Project