Dan*_*mov 33 garbage-collection xamarin.ios xamarin
注意:我创建了一个简单的项目 - 您可以看到故事板之间
UIButton和CustomButton故事板中的切换类型如何改变GC行为.
我正试图让我的脑袋缠绕着MonoTouch垃圾收集器.
该问题类似于MT 4.0中修复的问题,但是使用了继承类型.
为了说明它,请考虑两个视图控制器,父级和子级.
子视图包含一个UIButton可以随时写入控制台的视图.
Controller的Dispose方法会引发异常,因此很难错过.
这里是子视图控制器:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
sayHiButton.TouchUpInside += (sender, e) =>
SayHi();
}
}
void SayHi()
{
Console.WriteLine("Hi");
}
protected override void Dispose (bool disposing)
{
throw new Exception("Hey! I've just been collected.");
base.Dispose (disposing);
}
Run Code Online (Sandbox Code Playgroud)
父视图控制器只显示子控制器并设置一个计时器来关闭它并运行GC:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var child = (ChildViewController)Storyboard.InstantiateViewController("ChildViewController");
NSTimer.CreateScheduledTimer(2, () => {
DismissViewController(false, null);
GC.Collect();
});
PresentViewController(child, false, null);
}
Run Code Online (Sandbox Code Playgroud)
如果你运行这个代码,它可以预测会ChildViewController.Dispose()从其终结器中调用内部崩溃,因为子控制器已被垃圾收集.凉.
现在打开故事板并将按钮类型更改为CustomButton.MonoDevelop将生成一个简单的UIButton子类:
[Register ("CustomButton")]
public partial class CustomButton : UIButton
{
public CoolButton (IntPtr handle) : base (handle)
{
}
void ReleaseDesignerOutlets()
{
}
}
Run Code Online (Sandbox Code Playgroud)
以某种方式改变按钮类型CustomButton足以欺骗垃圾收集器使思维儿童控制器还没有资格收集.
怎么会这样?
Rol*_*nge 46
这是一个不幸的副作用MonoTouch(谁是垃圾收集)必须住在一个参考计数世界(ObjectiveC).
需要一些信息才能了解正在发生的事情:
在您的情况下发生的是一个循环,它跨越MonoTouch/ObjectiveC桥,由于上述规则,GC无法确定是否可以收集循环.
这是发生的事情:
现在您看到CustomButton实例将不会被释放,因为它的引用计数为2.并且不会释放ChildViewController实例,因为CustomButton的事件处理程序具有对它的引用.
有几种方法可以打破周期来解决这个问题:
[1]这是因为托管对象可能包含用户状态.对于镜像相应本机对象(例如托管UIView实例)的托管对象,MonoTouch知道实例不能包含任何状态,因此只要没有托管代码具有对托管实例的引用,GC就可以收集它.如果稍后需要托管实例,我们只需创建一个新实例.
| 归档时间: |
|
| 查看次数: |
9408 次 |
| 最近记录: |