【发布时间】:2011-06-21 15:19:00
【问题描述】:
我观察到一些会影响任何程序的内存消耗的东西,我想提出一些想法。
我用 UIViewController 和 UINavigationViewController 创建了一个非常简单的测试项目。我推我的 ViewController,然后我弹出它。 GC 完成了它的工作,我的 ViewController 被释放(调用了析构函数)。但是,如果我创建一个 UIButton 并注册到它的一个事件(例如:TouchInsideUp),那么我的 ViewController 不会被释放。我需要取消注册该事件才能释放我的 ViewController。为了确保这不是时间问题,我的测试应用程序有一个调用 GC.Collect() 的按钮。
我不明白的是,如果一个对象可以从任何线程的堆栈或静态变量访问,它就会保持活动状态。如果我的 ViewController 有资格进行垃圾收集,那么 UIButton 也将是。该事件不应导致 ViewController 保留在内存中,因为 GC 无法访问 UIButton。在我的例子中,ViewController 只被 NavigationController 使用,所以一旦它被弹出,它就应该被收集起来。
在新的分析器(单声道 2.10)的帮助下,我也许会找到一个合乎逻辑的答案,但现在,我很困惑。任何想法?
已编辑:这里有一些代码可以帮助理解我的情况。
我的测试 ViewController 非常简单
public class TestViewController : UIViewController{
~TestViewController(){ Console.WriteLine("Finalizer called"); }
public UIButton Button {get; set;}
public override ViewDidLoad(){
base.ViewDidLoad();
// If I remove the event registering, my TestViewController is collected.
Button = new UIButton();
Button.TouchUpInside += ButtonTouchEventHandler;
View.AddSubview(Button);
}
void ButtonTouchEventHandler(object sender, EventArgs e){}
}
我的 MainWindow 有一个 NavigationController,它执行以下操作:
- 它推送了一个新的 TestViewController 实例(因此只有 NavigationController 引用了 TestViewController 实例)
- TestViewController 通过标准后退按钮弹出(如果我没有注册到 TouchUpInside,TestViewController 的终结器会被调用)
- 当我返回到 MainWindow 时,一个按钮允许我调用 GC.Collect 来确定。
【问题讨论】:
-
如果没有看到您的解决方案,就不可能确切地说出发生了什么。
-
我添加了一些代码和解释。我想知道的是,在后台,事件注册是否涉及固定内存或静态变量(最终事件处理非托管资源,所以也许不仅仅是标准的 .Net 事件)。
-
谢谢,您的代码帮助我发现了问题。在某些情况下,这可能会导致对象图被保留,直到断开处理程序。我已经在下一个 monotouch 中解决了这个问题。
-
酷,这证实了我并不完全疯了 :) 也许你应该发布一个我可以标记为 ONE 的官方答案。
-
最后一件事。我发现了另一个使用 AddSubview 的案例。不过这一次,我会把它发布到 MonoTouch 的 bugzilla 系统中。
标签: garbage-collection xamarin.ios