Bug 40955 - Memory leak with FormsAppCompatActivity and NavigationPage
Summary: Memory leak with FormsAppCompatActivity and NavigationPage
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 2.2.0
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: Bugzilla
Depends on:
Reported: 2016-05-08 01:56 UTC by Andrew Hall
Modified: 2016-07-01 18:47 UTC (History)
14 users (show)

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

App1 and App1-FormsAppCompatActivity projects. (149.78 KB, application/x-zip-compressed)
2016-05-08 01:56 UTC, Andrew Hall

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:

Description Andrew Hall 2016-05-08 01:56:58 UTC
Created attachment 15939 [details]
App1 and App1-FormsAppCompatActivity projects.

Xamarin 4.0.3
Xamarin Forms
All other Xamarin stuff in NuGet 23.3.0
VS 2015 Enterprise Update 2

When using a MainActivity that inherits from FormsAppCompatActivity with a MasterDetailPage, NavigationPages are not released and leak memory.  This behaviour is not observed when using a MainActivity that inherits from FormsApplicationActivity.

Steps to reproduce:

Two projects are attached:
- App1 uses FormsApplicationActivity
- App1-FormsAppCompatActivity uses FormsAppCompatActivity

The two are identical, except App1 was modified using the steps from this article to add the Material Design: https://blog.xamarin.com/material-design-for-your-xamarin-forms-android-apps/

In the application there is a MasterDetailPage - set up is copied from here: https://developer.xamarin.com/guides/xamarin-forms/user-interface/navigation/master-detail-page/

In the application there are three pages you can navigate to.  All are identical, except natigavting to "Reminders" (ReminderPage.xaml.cs) will call GC.Collect() (a few times..).
When natigavting to a page, a NavigationPageEX is used as the "Detail" page which allows access to the destructor and also keeps an instance count.

In App1, when GC.Collect() is called the NavigationPageEX destructor is called as expected.
In App1-FormsAppCompatActivity, the desctructor in NavigationPageEX is never called, and the instance count increases unbounded.
Comment 1 Peter Bro 2016-06-09 06:35:59 UTC
We are experiencing the same issue with the severe memory leak when using the FormsAppCompatActivity in the main activity. 

When running with the Xamarin Profiler we can see that the majority of objects and allocated memory are never freed. 

We tried to change back to using non-AppCompat (and thereby non-material design) 
by using the FormsApplicationActivity instead. This made a significant memory leak improvement.

When we used the AppCompat the application quickly went to a working set of 150 Mb and it kept on increasing.
When we used FormsApplicationActivity instead then it started at 24 Mb and pretty much stayed there.

We am primary testing on android 4.2.2 and 4.4.4. 
XF version, 
Xamarin.Android.Support.v7.AppCompat version 23.3.0.
Comment 2 Jacob Biehl 2016-06-18 00:43:53 UTC
We are having the same issue.  In our testing, we also see that pages pushed to the navigation stack are also not properly destroyed.  As a simple test, we extended the test code attached to this bug by putting a chain of pages off of contacts using Navigation.PushAsync().  

In the FormsAppCompatActivity version, none of the pages are destroyed.  Conversely, in FormsApplicationActivity all pages are properly disposed when the garbage collection is performed.

This has turned into a no-ship bug for my team -- navigating around 10-15 images intense pages quickly swells the app to trigger OOM faults.

We are testing agains Android 6.0.1, XF, v7.AppCompat 23.3.0.
Comment 3 Pluspole Developer 2016-06-19 11:21:50 UTC
In our team we rely on this to work properly, it's a no-ship bug for us as well.
Comment 4 Samantha Houts [MSFT] 2016-06-27 18:32:39 UTC
Should be fixed in 2.3.1-pre1
Comment 5 Peter Bro 2016-06-28 08:02:38 UTC
Thanks! Looking forward to test it :-)
Comment 6 Jacob Biehl 2016-06-30 22:43:32 UTC
This doesn't seem to be fixed in 2.3.1-pre1 on nuget.  

It's not in the list of bugs addressed, so perhaps the simple answer here is that it didn't make it into that build.  However, when using the new library with the sample code provided by Andrew Hall the issue still exists.  The pages are never garbage collected and the memory alloc continues to monotonically grow.
Comment 7 E.Z. Hart [MSFT] 2016-06-30 23:30:56 UTC
(In reply to Jacob Biehl from comment #6)
> This doesn't seem to be fixed in 2.3.1-pre1 on nuget.  
> It's not in the list of bugs addressed, so perhaps the simple answer here is
> that it didn't make it into that build.  However, when using the new library
> with the sample code provided by Andrew Hall the issue still exists.  The
> pages are never garbage collected and the memory alloc continues to
> monotonically grow.

The fix is definitely in the 2.3.1-pre1 nuget packages. I've tested the sample project with the 2.3.1-pre1 packages, and verified that the destructor for the NavigationPage (which was never called in the previous version) is now being called, indicating that it is being collected. 

If you're still seeing a leak behavior, it may be due to other problems with releasing resources - if you could attach a repro project demonstrating the issue to this bug, we'll take a look.
Comment 8 Jacob Biehl 2016-06-30 23:42:57 UTC
We're using the exact code provided in "App1-FormsAppCompatActivity" attached to this bug.  Only difference is moving the package for XF up to 2.3.1 pre1.  Nothing else is different.  

We can trap the NavigationPageEX constructor and observe the counter increasing.  The destructor is never called.  Navigating from page to page, we can get the counter up to over 50 instances, clearly indicating the GC is not being invoked.

Is there another package dependency for this change?  Specific version of Xamarin-Android we should be testing against?
Comment 9 E.Z. Hart [MSFT] 2016-07-01 00:21:41 UTC
Right now I'm testing using Xamarin.Android (from Visual Studio). Which version and IDE are you using? 

Just to be clear, here's how I'm testing this:

1. Setting a breakpoint in the NavigationPageEX destructor at the line "_counter--;"
2. Clicking on "Contacts" several times to allocate instances of NavigationPageEx
3. Clicking on "TodoList" several times to allocate more instances of NavigationPageEx
4. Clicking on "Reminders", which calls "GC.Collect()" several times; this causes the breakpoint in the destructor to be hit. 

I have the linker disabled (set to "None") in the Android project. I also have the Android Device Monitor turned on and monitoring the application's heap; I can see it growing throughout steps 2 and 3, and see it decrease after step 4. 

Does that roughly match the steps you're using to test? I want to make sure I'm not missing a step before I start digging into this.
Comment 10 Andrew Hall 2016-07-01 00:39:21 UTC

I just tested and it seems to be fixed for me too.

Did you do the whole clean your solution and delete obj/bin directories from previous builds (and also delete the app on your device)?
Comment 11 Jacob Biehl 2016-07-01 18:47:42 UTC
Thanks everyone -- Andrew's point about the obj directory seemed to be the issue.  Once cleared out, we are now seeing the destructor being called.

Indeed the issue is resolved.