为什么MonoTouch GC无法使用refcount> 1来杀死托管对象?

Dan*_*mov 9 garbage-collection xamarin.ios

我想我已经接近了解Mono GC和ObjC如何重新计算在一起生活.

它的工作方式是当本机对象的引用计数为1时,我们不会阻止托管实例进行垃圾回收.一旦引用计数增加到1以上,我们就会阻止托管实例收集垃圾.

这是因为托管对象可能包含用户状态.对于镜像相应本机对象(例如托管UIView实例)的托管对象,MonoTouch知道实例不能包含任何状态,因此只要没有托管代码具有对托管实例的引用,GC就可以收集它.如果稍后需要托管实例,我们只需创建一个新实例.

因此,如果我创建了一个CustomButton继承UIButton,将其作为子视图添加到我的View,让托管引用滑出范围然后运行GC,此托管 CustomButton仍然不符合收集条件.

为什么不能收集?当然它可能具有类似属性的托管状态,但是如果没有来自托管对象的链接,谁关心这个状态?它可能也只是消失,为什么不能呢?

我正在考虑一个可能的原因:订阅CustomButton事件不会使GC保持活动状态,因此当收集对象时,事件会停止触发.这可能会导致意外行为.

它是否正确?是否有其他原因使托管对象保持活动状态,即使没有人链接它?

Rol*_*nge 7

为什么不能收集?当然它可能具有类似属性的托管状态,但是如果没有来自托管对象的链接,谁关心这个状态?它可能也只是消失,为什么不能呢?

本机代码可能具有对该对象的引用,这可能导致该对象稍后再次重新出现到托管代码.

我相信代码示例会说明会发生什么:

class MyView : UIView {
    public string ImportantSecret;
}

class AppDelegate : UIApplicationDelegate {
    UIViewController vc;
    public override bool FinishedLaunching (UIApplication app, 
                                            NSDictionary options)
    {
        var myView = new MyView ();
        myView.ImportantSecret = "MonoTouchRocks";

        vc = new UIViewController ();
        vc.View = new UIView ();
        vc.View.AddSubView (myView);

        // When this method returns the only place where myView is referenced
        // is from inside the *native* Subviews collection.

        BeginInvokeOnMainThread (() =>
        {
            Console.WriteLine (((MyView) vc.Subviews [0]).ImportantSecret);
            // If the MyView instance was garbage collected and recreated
            // automatically at this point, ImportantSecret would be null.
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

重要说明:此代码仅用于说明GC无法收集可能具有状态的托管对象的原因.这个特定的示例实际上不会忘记重要的秘密,因为Subviews数组会自动缓存在托管代码中 - 但这通常不正确.