4

In my Xamarin app, I have Five pages, Page 1, Page 2, Page 3, Page 4 and Page 5. When navigating from Page 5 to Page 3, I called Navigation.RemovePage() to remove Page 4 in NavigationStack. However, there is huge memory leak when calling RemovePage(). I want to know if there is any workaround to avoid memory leak when trying to remove the page between two pages in the NavigationStack? (Since Page 3 is not the Root Page, so I can't use PopToRootAsync())

Also, anyone can explains me why using PushModalAsync() will remove all pages in NavigationStack and only leaves the current added page and in both NavigationStack and ModalStack.

Thank you very much.

Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
Leo
  • 49
  • 5
  • 1
    How did you determine that there is a memory leak? – Mouse On Mars Jul 23 '20 at 19:31
  • The app is running on the UWP. I use visual studio's diagnostic tool to see the memory usage builds up very fast. And in the Task Manager, it also shows memory usage builds up pretty fast. In Android and iOS platform is working fine without memory leak. – Leo Jul 23 '20 at 19:54
  • Do you know if the garbage collector ran when you are comparing these memory values? Just want to make sure it is a genuine memory leak and not simply uncollected memory that is lingering until the GC cleans up – Mouse On Mars Jul 24 '20 at 19:29
  • @MouseOnMars First, I am not sure when the GC can release the memory and the memory usage seems never reduces on the my UWP. There is a sample written by Nico from Page 1 to Page 2, and Page 2 to Page 3 and then Remove Page 2 and back to the Page 1 also cause memory leak as Visual Studio Diagnostic Tools shows. You could test this to see if the memory leak happens. Here is the link [link](https://github.com/Revfeng/NavigationSample1.git). Thank you very much. – Leo Jul 27 '20 at 16:23

2 Answers2

1

In Xamarin, how to avoid memory leak when using Navigation.RemovePage()

During testing, it will not leak memory when the RemovePage method is called.

private void Button_Clicked(object sender, EventArgs e)
{
    Navigation.RemovePage( Navigation.NavigationStack.Where(a=> a is Page4).FirstOrDefault());
}

anyone can explains me why using PushModalAsync() will remove all pages in NavigationStack and only leaves the current added page and in both NavigationStack and ModalStack.

The matched with PushModalAsync navigation behavior in UWP platform is showing a ContentDialog. And it will not effect NavigationStack

The following is the test code.

private void PushClick(object sender, EventArgs e)
{
    Navigation.PushModalAsync(new MainPage());
    foreach (var item in Navigation.NavigationStack)
    {
        System.Diagnostics.Debug.WriteLine(item.GetType().Name);
    }
}

For complete code sample please refer this link.

Mouse On Mars
  • 1,086
  • 9
  • 28
Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
  • Thank you very much Nico. I have tested your complete sample code. I added something on the code which shows RemovePage() memory leak. I am not sure whether this is called memory leak. The sample is Page1 -> Page 2 and Page 2 -> Page 3 and then there is a button named ToPage1 which remove the Page 2 using RemovePage() before pop back to the Page 1. I tested it by clicking very fast and then the memory usage in the Visual Studio Diagnostic Tool shows the memory increases slowly since there is no other bindings? Could you help me test it out to see if you are getting the same result as me? – Leo Jul 27 '20 at 15:53
  • For the revised code, refer to this [link](https://github.com/Revfeng/NavigationSample1.git). I am not sure if this is memory leak. Thank you very much. @Nico Zhu – Leo Jul 27 '20 at 16:16
  • I think the sample code you are given doesn't have Binding. RemovePage() api might remove the layout the content page, but it will not remove the bindings of the page which could be the reason of the memory leak happens on my app using MVVM pattern. Do you have any idea how can I resolve this issue? Thank you very much. – Leo Jul 27 '20 at 18:40
  • For the testing, Page2's ViewModel will cause memory rise. but it's normal, because you have implement 10000 string object in it. And when you remove the page2 from navigation stack, the page2 instance will not destroy immediately. the memory collection will be managed by the system. – Nico Zhu Jul 28 '20 at 08:10
  • So, you mean that it is fine with the memory increases. This is not a memory leak issue? However, this is just an sample, when people are using the app (not this one), it will cause the same issue and then builds up the memory very fast until the app memory usage becomes 500MB or 1GB and then it becomes really slow. Is there any way to resolve it? Thank you very much. @Nico – Leo Jul 28 '20 at 13:56
  • Yep, it's normal, uwp is not native app, it's run in the [clr](https://learn.microsoft.com/en-us/dotnet/standard/clr), so the memory will be manage by the clr(auto collection). In general, ListView and collectionView control is virtualization, it will not render items once for all. If you want to optimal performance. we suggest cut the data source to number pages. Avoid reading too much data at once. – Nico Zhu Jul 28 '20 at 14:08
  • 1
    Thanks Nico. Actually the memory leak still happens on the app when calling RemovePage() api if the removed page contains bindings and will never addressed by the garbage collector either in production or release mode. But still thank you very much for your help. – Leo Jul 29 '20 at 19:36
1

A simple test to check if your app leaks memory might be helpful. Enforce garbage collection after the operation you are investigating. Understanding how the .net garbage collector works might also be helpful link. Look at the memory consumption before you remove the page and after. For test purposes force garbage collection right after the page is removed

private void Button_Clicked(object sender, EventArgs e)
{
    Navigation.RemovePage( Navigation.NavigationStack.Where(a=> a is Page4).FirstOrDefault());
    GC.Collect(2, GCCollectionMode.Forced);
} 
Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
Mouse On Mars
  • 1,086
  • 9
  • 28
  • During testing GC will not clean memory immediately, CLR will clean unused object base on object reference type (weak or strong). And above all will process automatically. – Nico Zhu Jul 29 '20 at 08:34
  • I am not sure I understand. Why only collect some generations? Independent of if you are using strong or weak references, once you remove the page, the page and all its associated UI and other objects you created should be "garbage collectable". It's like cutting off a branch of a tree, everything attached to this branch should be collectable. If it is not you have a memory leak – Mouse On Mars Jul 29 '20 at 20:49
  • Thank you very much Nico. Will try your way to test the memory leak using your way. And will let you know what happened. – Leo Aug 02 '20 at 19:31