我遇到了一个问题,页面对象一旦被导航离开,就不会被垃圾收集。我整理了一个非常基本的示例,演示了使用 NavigationPage 和 PushAsync 方法时出现的问题。该页面使用弱引用列表显示“活动”页面的数量:
public class AppNavigationPage
{
private static List<WeakReference> pageRefs = new List<WeakReference>();
public static Page GetMainPage()
{
return new NavigationPage(CreateWeakReferencedPage());
}
private static Page CreateWeakReferencedPage()
{
GC.Collect();
var result = CreatePage();
pageRefs.Add(new WeakReference(result));
// Add a second unreferenced page to prove that the problem only exists
// when pages are actually navigated to/from
pageRefs.Add(new WeakReference(CreatePage()));
GC.Collect();
return result;
}
private static Page CreatePage()
{
var page = new ContentPage();
var contents = new StackLayout();
contents.Children.Add(
new Button
{
Text = "Next Page",
Command = new Command(() => page.Navigation.PushAsync(CreateWeakReferencedPage()))
});
contents.Children.Add(
new Label
{
Text = string.Format(
"References alive at time of creation: {0}",
pageRefs.Count(p => p.IsAlive)),
HorizontalOptions = LayoutOptions.CenterAndExpand
});
page.Content = contents;
return page;
}
}
单击“下一页”按钮时,将创建一个新页面,其中带有固定值标签,显示创建此页面时活动的页面引用数。每次单击按钮时,您都会明显看到这个数字增加 1。我的理解是,当您单击导航页面上的“后退”时,视图应该从堆栈中弹出并丢弃(允许它被 GC) 。但是,当我运行此测试代码时,它表明在我们返回后,此视图将保留在内存中。这可以通过多次单击“下一页”直到引用计数为 3 来证明。如果您然后单击“上一步”,然后单击“下一页”,我相信引用计数仍应为 3(表明旧页面在新页面之前已被 GC)创建了一个)但是新的引用计数现在是 4。
这似乎是 iOS 的 X-Forms 导航实现中的一个相当严重的错误(我还没有在其他平台上测试过这个错误),我的猜测是它在某种程度上与此处描述的强引用循环问题有关:http://developer.xamarin.com/guides/cross-platform/application_fundamentals/memory_perf_best_practices/ http://developer.xamarin.com/guides/cross-platform/application_fundamentals/memory_perf_best_practices/
有其他人遇到过这个问题和/或提出解决方案/解决方法吗?其他人会同意这是一个错误吗?
作为补充,我做了第二个不涉及 NavigationPage 的示例(因此必须使用 PushModalAsync 代替),并发现我遇到了同样的问题,因此这个问题看起来并不是 NavigationPage 导航所独有的。作为参考,该(非常相似)测试的代码如下:
public class AppModal
{
private static List<WeakReference> pageRefs = new List<WeakReference>();
public static Page GetMainPage()
{
return CreateWeakReferencedPage();
}
private static Page CreateWeakReferencedPage()
{
GC.Collect();
var result = CreatePage();
pageRefs.Add(new WeakReference(result));
// Add a second unreferenced page to prove that the problem only exists
// when pages are actually navigated to/from
pageRefs.Add(new WeakReference(CreatePage()));
GC.Collect();
return result;
}
private static Page CreatePage()
{
var page = new ContentPage();
var contents = new StackLayout();
contents.Children.Add(
new Button
{
Text = "Next Page",
Command = new Command(() => page.Navigation.PushModalAsync(CreateWeakReferencedPage()))
});
contents.Children.Add(
new Button
{
Text = "Close",
Command = new Command(() => page.Navigation.PopModalAsync())
});
contents.Children.Add(
new Label
{
Text = string.Format(
"References alive at time of creation: {0}",
pageRefs.Count(p => p.IsAlive)),
HorizontalOptions = LayoutOptions.CenterAndExpand
});
page.Content = contents;
return page;
}
}