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