MonoTouch对象引用可防止垃圾回收

时间:2013-07-01 15:17:45

标签: memory-leaks xamarin.ios garbage-collection

我有一个奇怪的问题,导致MonoTouch内存泄漏。这是我的设置。

CaseTabController - UITabBarController
-- CaseMediaItemsController - UIViewController
-- CaseInfoController (irrelevant) - UIViewController

子控制器显示为选项卡。从子控制器,我试图将一些NavigationItem(s)添加到父UITabBarController。但是,当我访问ParentViewController时,会保留一个引用,使我的对象保持活动状态并且永远不会被垃圾回收。

仅将以下代码添加到子UIViewController的ViewDidLoad会导致内存泄漏。

var ni = ParentViewController.NavigationItem;
ni = null;

可能父UITabBarController从未被处理掉,因为我的子标签引用了它。这是HeapShot的输出。

访问ParentViewController来自儿童标签

HeapShot with memory leak

无法访问儿童标签ParentViewController

HeapShot without memory leak

请注意,除了步骤之外,每个内存快照都在执行相同的操作。请注意快照WITHOUT引用ParentViewController的实例如何更少,因为正在处理它们。它们处理得如此之快,以至于我在查看相关控制器时实际拍摄了快照。没有访问ParentViewController的快照正在访问另一个控制器。在每种情况下,UITabBarController都已从UINavigationController中弹出。

为什么CaseMediaItemsController在访问ParentViewController时维护对CaseTabController的引用的任何想法?

1 个答案:

答案 0 :(得分:6)

要获得完整答案,请查看http://xamarin.com/evolve/2013#session-0w86u7bco2

基本上,通过引用子节点中的父节点,您有一个循环,并且将NavigationItem设置为null是不够的,您还必须Dispose()它。但是你必须确保在这个时候Dispose()对象。

var ni = ParentViewController.NavigationItem;
ni.Dispose ();
ni = null;

您也可以不保留对NavigationItem的强引用,如果您需要ni变量以方便起见,请将其设为WeakReference<UINavigationItem>。这将允许它被垃圾收集。

WeakReference<UINavigationItem> ni;

public override void ViewDidLoad ()
{
    ni = new WeakReference<UINavigationItem> (ParentViewController.NavigationItem);

    //Nothing else here.
}

然后您可以像这样使用ni

if (ni.Target != null)
    Console.WriteLine (ni.Target.Title);