UIView事件和垃圾回收

4
我注意到一个可以影响任何程序内存消耗的问题,希望得到一些想法。
我创建了一个非常简单的测试项目,包括一个UIViewController和一个UINavigationViewController。我推出了我的ViewController,然后又将其弹出。GC执行了它的任务,我的ViewController被释放了(析构函数被调用)。但是,如果我创建一个UIButton并注册到其中一个事件(例如:TouchInsideUp),那么我的ViewController就不会被释放。我需要取消注册才能释放我的ViewController。为了确保这不是时间问题,我的测试应用程序有一个按钮来调用GC.Collect()。
我不理解的是,如果一个对象可以从任何线程的堆栈或静态变量中访问,那么它将被保持活动状态。如果我的ViewController可以进行垃圾回收,那么UIButton也应该可以进行垃圾回收。事件不应该导致ViewController在内存中保留,因为UIButton不可由GC访问。在我的情况下,ViewController仅由NavigationController使用,因此一旦弹出它应该总是被收集。
借助新的分析器(mono 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,并且它执行以下操作:

  1. 它推送了TestViewController的一个新实例(因此只有NavigationController有对TestViewController实例的引用)
  2. 如果我没有注册TouchUpInside,TestViewController将通过标准返回按钮弹出(如果我不注册TouchUpInside,TestViewController的终结器会被调用)
  3. 当我返回到MainWindow时,一个按钮允许我调用GC.Collect以确保。

没有看到你的解决方案,很难准确地说明发生了什么。 - Geoff Norton
我添加了一些代码和解释。我想知道的是,在底层,事件注册是否涉及固定内存或静态变量(最终,该事件处理非托管资源,因此可能存在比标准的.Net事件更多的内容)。 - Jonathan Clément
谢谢,你的代码帮助我找到了问题。有一种情况会导致对象图一直保留,直到断开处理程序。我已经在下一个Monotouch中修复了这个问题。 - Geoff Norton
很好,这证实了我不是完全疯了 :) 也许你应该发布一个官方答案,我可以标记为唯一的答案。 - Jonathan Clément
最后一件事。我发现另一个使用AddSubview的案例。但这次,我将把它发布到MonoTouch的bugzilla系统中。 - Jonathan Clément
1个回答

0

是的,在这种模式下,对象图可能会被锁定,我已经在 MonoTouch 的下一个主要版本(MonoTouch 4)中修复了它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接