在 Xamarin 中,使用 Navigation.RemovePage() 时如何避免内存泄漏
Posted
技术标签:
【中文标题】在 Xamarin 中,使用 Navigation.RemovePage() 时如何避免内存泄漏【英文标题】:In Xamarin, how to avoid memory leak when using Navigation.RemovePage() 【发布时间】:2020-11-13 12:06:14 【问题描述】:在我的 Xamarin 应用程序中,我有五个页面,第 1 页、第 2 页、第 3 页、第 4 页和第 5 页。从第 5 页导航到第 3 页时,我调用 Navigation.RemovePage() 以删除 NavigationStack 中的第 4 页.但是,调用 RemovePage() 时存在巨大的内存泄漏。我想知道在尝试删除 NavigationStack 中两个页面之间的页面时是否有任何解决方法可以避免内存泄漏? (由于第3页不是根页,所以我不能使用PopToRootAsync())
另外,任何人都可以向我解释为什么使用 PushModalAsync() 会删除 NavigationStack 中的所有页面,只保留当前添加的页面以及 NavigationStack 和 ModalStack 中的页面。
非常感谢。
【问题讨论】:
您是如何确定存在内存泄漏的? 应用在 UWP 上运行。我使用 Visual Studio 的诊断工具来查看内存使用量的增长速度非常快。在任务管理器中,它还显示内存使用量增加得非常快。在 android 和 ios 平台上运行良好,没有内存泄漏。 你知道在比较这些内存值时垃圾收集器是否运行了吗?只是想确保它是真正的内存泄漏,而不仅仅是在 GC 清理之前一直存在的未收集内存 @MouseOnMars 首先,我不确定 GC 何时可以释放内存,而且我的 UWP 上的内存使用量似乎永远不会减少。 Nico 编写了一个示例,从第 1 页到第 2 页,从第 2 页到第 3 页,然后删除第 2 页并回到第 1 页也会导致内存泄漏,如 Visual Studio 诊断工具所示。您可以对此进行测试以查看是否发生内存泄漏。这是链接link。非常感谢。 【参考方案1】:在 Xamarin 中,使用 Navigation.RemovePage() 时如何避免内存泄漏
在测试过程中,调用RemovePage
方法时不会泄露内存。
private void Button_Clicked(object sender, EventArgs e)
Navigation.RemovePage( Navigation.NavigationStack.Where(a=> a is Page4).FirstOrDefault());
任何人都可以向我解释为什么使用 PushModalAsync() 会删除
NavigationStack
中的所有页面,并且只保留当前添加的页面以及 NavigationStack 和 ModalStack 中的页面。
UWP 平台中与PushModalAsync
匹配的导航行为显示ContentDialog
。而且不会影响NavigationStack
以下是测试代码。
private void PushClick(object sender, EventArgs e)
Navigation.PushModalAsync(new MainPage());
foreach (var item in Navigation.NavigationStack)
System.Diagnostics.Debug.WriteLine(item.GetType().Name);
完整的代码示例请参考link。
【讨论】:
非常感谢尼科。我已经测试了您的完整示例代码。我在显示 RemovePage() 内存泄漏的代码上添加了一些内容。我不确定这是否称为内存泄漏。示例是 Page1 -> Page 2 和 Page 2 -> Page 3,然后有一个名为 ToPage1 的按钮,它使用 RemovePage() 删除第 2 页,然后再弹出到第 1 页。我通过非常快速地单击来测试它,然后Visual Studio 诊断工具中的内存使用情况显示内存增加缓慢,因为没有其他绑定?你能帮我测试一下,看看你得到的结果和我一样吗? 修改后的代码可以参考这个link。我不确定这是否是内存泄漏。非常感谢。 @妮可朱 我认为您提供的示例代码没有绑定。 RemovePage() api 可能会删除内容页面的布局,但它不会删除页面的绑定,这可能是使用 MVVM 模式在我的应用程序上发生内存泄漏的原因。你知道我该如何解决这个问题吗?非常感谢。 为了测试,Page2的ViewModel会导致内存上升。但这很正常,因为您在其中实现了 10000 个字符串对象。当您从导航堆栈中删除 page2 时, page2 实例不会立即销毁。内存集合将由系统管理。 所以,你的意思是内存增加就可以了。这不是内存泄漏问题吗?然而,这只是一个示例,当人们使用应用程序(不是这个)时,它会导致同样的问题,然后非常快速地建立内存,直到应用程序内存使用量变为 500MB 或 1GB,然后变得非常慢。有什么办法可以解决吗?非常感谢。 @尼科【参考方案2】:检查您的应用是否泄漏内存的简单测试可能会有所帮助。在您正在调查的操作之后强制执行垃圾回收。了解 .net 垃圾收集器的工作原理也可能会有所帮助 link。 在删除页面之前和之后查看内存消耗。出于测试目的,在页面被删除后立即强制垃圾回收
private void Button_Clicked(object sender, EventArgs e)
Navigation.RemovePage( Navigation.NavigationStack.Where(a=> a is Page4).FirstOrDefault());
GC.Collect(2, GCCollectionMode.Forced);
【讨论】:
在测试期间,GC 不会立即清理内存,CLR 会根据对象引用类型(弱或强)清理未使用的对象。最重要的是会自动处理。 我不确定我是否理解。为什么只收集几代?无论您使用的是强引用还是弱引用,一旦您删除页面,该页面及其所有关联的 UI 以及您创建的其他对象都应该是“可收集的垃圾”。就像砍掉一棵树的树枝,附着在树枝上的所有东西都应该是可以收藏的。如果不是你有内存泄漏 非常感谢尼科。将尝试使用您的方式测试内存泄漏。并且会让你知道发生了什么。以上是关于在 Xamarin 中,使用 Navigation.RemovePage() 时如何避免内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin.Forms学习之Page Navigation
Xamarin.Forms学习之Page Navigation
Xamarin - 在等待Navigation.PushAsync时避免返回按钮标题
Xamarin.Forms学习之Page Navigation
我们可以覆盖 Xamarin.forms 中的 NAVIGATION BACK BUTTON 按下吗?
TabbedPage 中的 Xamarin Forms Prism Navigation 表现为 PushModelAsync 或导航栏消失