ton*_*444 19 xamarin.ios xamarin xamarin.forms
我遇到了一个问题,一旦它们被导航出来,页面对象就不会被垃圾收集.我已经汇总了一个非常基本的示例,它演示了使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
单击"下一页"按钮时,将创建一个带有固定值标签的新页面,该标签显示在创建此页面时活动的页面引用数.每次点击该按钮,你明明看到1.我的理解这个数字上升时间是,当你点击"返回"导航页面上,认为应该弹出堆栈和扔掉(使它GC'd) .但是,当我运行此测试代码时,它表示在我们返回之后,此视图将保留在内存中.这可以通过点击下一页几次,直到引用计数为3.如果然后单击后退,然后下一页证明,我认为引用计数应该还是3(表示旧页面之前新被GC'd一个被创建了)但是新的引用计数现在是4.
这似乎是在为iOS的X形式的导航实施(我没有测试过这对于其他平台),我的猜测被它某种程度上与这里所描述的强参照周期的问题相当严重的错误: HTTP://开发商. 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;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为您看到的是异步导航的副作用,而不是内存泄漏。您可以选择终结器并创建 MyPage(而不是 ContentPage)的实例,而不是 WeakReferences。
public class MyPage: ContentPage
{
private static int count;
public MyPage()
{
count++;
Debug.WriteLine("Created total " + count);
}
~MyPage()
{
count--;
Debug.WriteLine("Finalizer, remaining " + count);
}
}
Run Code Online (Sandbox Code Playgroud)
下一个技巧是添加延迟的 GC.Collect() 调用,例如:
private static Page CreateWeakReferencedPage()
{
GC.Collect();
var result = CreatePage();
var ignore = DelayedGCAsync();
return result;
}
private static async Task DelayedGCAsync()
{
await Task.Delay(2000);
GC.Collect();
}
Run Code Online (Sandbox Code Playgroud)
您会注意到,实例在此延迟收集(输出窗口)内被垃圾收集。根据 Xamarin GarbageCollector:我怀疑它有严重缺陷。到处都是小错误,但不是那么大。也就是说,处理 Android 中的垃圾收集特别棘手,因为有两个垃圾收集 - Dalvik 的和 Xamarin 的。不过那是另一回事了。
| 归档时间: |
|
| 查看次数: |
4575 次 |
| 最近记录: |