Monotouch(Xamarin.iOS)内存泄漏

时间:2013-10-10 14:43:28

标签: c# ios xamarin.ios xamarin

我有一个具有复杂视图层次结构的应用程序,其中一个视图控制器(让我们称之为RootVC)可以导致许多其他视图。当我弹出RootVC时,我想完全释放它。我没有将参考文献存储在字段或其他地方,并认为这就足够了。但是最近我检查了Xamarin的Heap Shot并在“All objects”部分看到RootVC的许多实例仍留在内存中。

例如:

sealed class VC1 : UIViewController
{
    ...

    private void OpenVC2()
    {
        var vc2 = new VC2();
        NavigationController.PushViewController(vc2, true);
    }
}

sealed class VC2 : UIViewController
{
    private UIButton button;
    public override ViewDidLoad()
    {
        ...
        button = new UIButton(frame);
        button.TouchUpInside += HandleButtonTouch;
        ...
    }

    private void HandleButtonTouch(object sender, EventArgs e)
    {
        NavigationController.PopViewControllerAnimated(true):
    }
}

以下是Heap Shot屏幕截图的链接(由于信誉不佳,无法将其发布为图片) - http://imgur.com/a/3MYBr#1

当我在VC2上时,我会在第一个屏幕截图中看到类似内容。

当我弹出VC2和VC1时,Heap Shot在第二张图像上显示。

出现几个VC2之后,它看起来像第三个截图。

他们永远不会被处理或最终确定,直到最后。即使通过根也无法达到它们。这是不可接受的,因为内存是有限的,并且所有这些VC2都在内存中,我们很容易得到内存警告或应用程序终止。

但是,如果我订阅/取消订阅View上的按钮事件,就会显示/消失:

sealed class VC2 : UIViewController
{
    private UIButton button;
    public override ViewDidLoad()
    {
        ...
        button = new UIButton(frame);
        ...
    }

    public override void ViewWillAppear(bool animated)
    {
        ...
        button.TouchUpInside += HandleButtonTouch;
    }

    public override void ViewDidDisappear(bool animated)
    {
        ...
        button.TouchUpInside -= HandleButtonTouch;
    }

    private void HandleButtonTouch(object sender, EventArgs e)
    {
        NavigationController.PopViewControllerAnimated(true):
    }
}

在这种情况下,VC2(及其所有视图等)在消失时会正确处理。调用~VC2(),并且Heap Shot中不再显示所有VC2。

所以,这是问题所在。我做错了什么?我应该订阅/取消订阅上述控制事件吗?或者这是Xamarin.iOS的内存泄漏?

1 个答案:

答案 0 :(得分:3)

会发生的是循环依赖(使用事件处理程序)跨越本机管理的边界,并且当前Xamarin.iOS运行时/ GC无法检测到此情况。

您已经找到了解决此问题的方法:通过删除事件处理程序来打破循环依赖关系。

以下是详细说明情况的视频:http://xamarin.com/evolve/2013#session-0w86u7bco2