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

Pau*_*opf 3 garbage-collection memory-leaks xamarin.ios

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

CaseTabController - UITabBarController
-- CaseMediaItemsController - UIViewController
-- CaseInfoController (irrelevant) - UIViewController
Run Code Online (Sandbox Code Playgroud)

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

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

var ni = ParentViewController.NavigationItem;
ni = null;
Run Code Online (Sandbox Code Playgroud)

可能父UITabBarController永远不会被处理,因为我的子选项卡引用它.这是HeapShot的输出.

通过访问ParentViewController从子TABS

HeapShot内存泄漏

无需访问ParentViewController儿童标签

HeapShot没有内存泄漏

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

CaseMediaItemsController在访问ParentViewController时是否维护对CaseTabController的引用的任何想法?

Ste*_*oix 6

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

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

var ni = ParentViewController.NavigationItem;
ni.Dispose ();
ni = null;
Run Code Online (Sandbox Code Playgroud)

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

WeakReference<UINavigationItem> ni;

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

    //Nothing else here.
}
Run Code Online (Sandbox Code Playgroud)

然后你可以ni像这样使用:

if (ni.Target != null)
    Console.WriteLine (ni.Target.Title);
Run Code Online (Sandbox Code Playgroud)