Bug 52597 - GREFs ListView and PopToRootAsync (Xamarin Forms 2.3.4.231 targeting Android)
Summary: GREFs ListView and PopToRootAsync (Xamarin Forms 2.3.4.231 targeting Android)
Status: CONFIRMED
Alias: None
Product: Forms
Classification: Xamarin
Component: Android ()
Version: 2.3.4
Hardware: PC Windows
: Normal major
Target Milestone: ---
Assignee: Chris King
URL:
Depends on:
Blocks:
 
Reported: 2017-02-17 09:37 UTC by Jean Martin
Modified: 2017-11-15 14:34 UTC (History)
4 users (show)

Tags: gref leak poptorootasync android listview ac
Is this bug a regression?: ---
Last known good build:


Attachments
The solution I used to investigate (54.80 KB, application/x-zip-compressed)
2017-02-17 09:37 UTC, Jean Martin
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 for Bug 52597 on Developer Community or GitHub if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: Developer Community HTML or GitHub Markdown
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:
Status:
CONFIRMED

Description Jean Martin 2017-02-17 09:37:35 UTC
Created attachment 19860 [details]
The solution I used to investigate

Hi, 

Here we have an application with a lot of ListViews and frequent crashes. Sometimes it reach the GREFs limit of the physical device, but it happend also multiple time on the emulator, because the limit is really low. Using the GREFs logging I was able to narrow the big part of the problem down to when we release a lot of screen with PopToRootAsync. When this happend no GREFs are released at all. 

To investigate this, I have created a new Forms solution to keep things simple. The solution contains only one page with a ListView and several buttons for tests. The first button reloads another instance of the (same) page with a populated ListView (3 items). If I click on it, I can see the GREFs increase in the output windows in Visual Studio. Then I also have one button to call the garbage collector and the others are button to pop pages in different ways.

This is becoming ugly now, when I load several instance (of the page) and the call PopToRootAsync without animation (a Xamarin Method), the GREFs never decrease. If I use the garbage collector multiple times (button Clean IT), it doesn't decrease. It I go drink a coffee and comeback and call the GC, it doesn't decrease. 

This is really a problem and probably a bug. I have done some reseach to find a workaround and tried a lot of (sometime random) things and compared GREFs metrics to find this: 

- If the PopAsync is animated, more GREFs are released. (why?)
- If I clear the ObservableCollection before the PopAsync more GREFs are released. (proly because items in ListView are released?)
- If I PopAsync the page from the view itself, a lot more GREFs are released. (this one sound like a X-File episode...)

So I created a recursive method in the view to do the same as a PopToRootAsync but on the view: 

//Homemade PopToRoot each view pop itself recursively
//must be on the view to work! (I don't know why...)
public async Task PopToRoot(bool animate)
{
	var nav = Application.Current.MainPage.Navigation;
	if (nav.NavigationStack.Count > 1) //Don't touch the root
		if (nav.NavigationStack[nav.NavigationStack.Count - 1].BindingContext is IDisposable) // Clean Collections if ViewModel Is Disposable
			(nav.NavigationStack[nav.NavigationStack.Count - 1].BindingContext as IDisposable).Dispose();

	await nav.PopAsync(animate); 

	if (nav.NavigationStack.Count > 1 && nav.NavigationStack[nav.NavigationStack.Count-1] is ListViewPage)
		await (nav.NavigationStack[nav.NavigationStack.Count - 1] as ListViewPage).PopToRoot(animate); //Recursive Pop
}

Using this method released the most GREFs. I have run some tests with other methods in my solution: 

- Xamarin PopToRootAsync not animated
- Xamarin PopToRootAsync animated 
- Recursive PopToRootAsync not animated 
- Recursive PopToRootAsync animated

I have defined a test protocol :

0) Load the App and click on CleanIT several times -> GC.Collect()
1) Write down the current GREF
2) Load the page 3 times 
3) Write down the current GREF
4) Use the tested method to PopToRootAsync
5) Click on (CleanIT) -> GC.Collect()
6) Write down the current GREF
7) Click on CleanIT multiple time (until GREFs is stabilized) 
8) Write down the current GREF
9) Calculate the delta between 8 and 1 (this should be the number of GREFs leaked)
10) GOTO 1

On the emulator the results are:

- Recursive PopToRootAsync animated: 14 GREFs not released
- Recursive PopToRootAsync not animated: 156  GREFs not released
- Xamarin PopToRootAsync animated: 125 GREFs not released
- Xamarin PopToRootAsync not animated: 185 GREFs not released

I tried on my Samsung A5 2016 Android 6.0 and the results are :

Recursive PopToRootAsync animated: 13 GREFs not released
Recursive PopToRootAsync not animated: 186 GREFs not released
Xamarin PopToRootAsync animated: 124 GREFs not released
Xamarin PopToRootAsync not animated: 186 GREFs not released

And Then I tried on a Arbor Gladius 5, Android 4.2 and the results are :

Recursive PopToRootAsync animated: 13 GREFs not released
Recursive PopToRootAsync not animated: 186 GREFs not released
Xamarin PopToRootAsync animated: 125 GREFs not released
Xamarin PopToRootAsync not animated: 185 GREFs not released

If I clean the collection before the Recursive PopToRootAsync animated: 14 GREFs are not released (this is really better than 185 leaked GREFs...)

I have attached the zip file of the solution with this post, if you like to test.

Thanks!
Comment 1 Jean Martin 2017-02-23 11:35:17 UTC
Xamarin.Forms 2.3.3.193 have the same problem.
Comment 2 Paul DiPietro [MSFT] 2017-02-24 21:12:56 UTC
Thank you very much for the reproduction and steps. Setting this to confirmed for the time being.
Comment 3 Jean Martin 2017-03-08 09:11:32 UTC
I have a lead on this bug.

I think the line 

rendererToRemove.Dispose();

Is missing in the not animated part of the method SwitchContentAsync in Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs somewhere between line 299 and 321, it's present in the animated part of the if above. 

I don't have the time to install Xamarin forms building environment and test my hypothesis, but it make sense.
Comment 4 Jean Martin 2017-03-08 09:33:16 UTC
PS: Thanks @Paul DiPietro for confirming this bug
Comment 5 Jean Martin 2017-03-17 10:16:25 UTC
I got the time to investigate my lead (see comment from 2017-03-08 09:11:32 UTC) and it was wrong the problem come from somewhere else I think.
Comment 6 Jean Martin 2017-04-13 13:11:12 UTC
Confirmed still occurred on 2.3.4.231
Comment 7 sibren 2017-11-15 14:34:53 UTC
Still occurs on 2.3.4.270.