2

我偶然发现了这个问题:ContentView 中的按钮导致 MonoTouch 运行时崩溃。Monotouch 4.0 中的错误?并且询问者对 Monotouch 的“更具侵略性”的垃圾收集器有问题。

  • 有人可以解释为什么在询问者的情况下会发出错误(收集了什么以及为什么?)?
  • “更具侵略性”是什么意思?我可以落入哪些陷阱?我应该避免什么?
  • 关于 iOS5:Apple 声称在 iOS5 中应用会收到一个内存警告,然后就会被杀死。与之前的任何其他版本不同,应用程序收到三个警告。这对 Monotouch 意味着什么?它将如何处理这种行为?

也许 Xamarin 团队中的一个可以总结一些注意事项并给出一个很好的解释?

我目前正在从 MT 3.2.6 升级到 MT 4.1,并且想检查我的代码并检查需要更改的内容。

4

5 回答 5

6

我们发现有时开发人员会遇到奇怪的问题,例如对话框有时会停留在屏幕上,有时它们会消失得无影无踪,也无法解释为什么会发生这种情况。

这通常发生在您创建 UIAlertView 并且不保留对它的引用时,因此就 MonoTouch 而言,该对象是垃圾(您没有从代码中引用它,因此您没有使用它)。

但对话框是立即从屏幕上消失还是稍后消失取决于垃圾收集器的启发式方法是否确定是时候运行收集了。如果您在收集之后创建了一个对话框,那么您的对话框很可能会留在屏幕上。但是如果你非常接近一个集合,或者如果你有一个后台进程消耗内存,那么就会触发 GC。

这通常让用户感到困惑,“为什么事情会随机消失”。答案是:如果你没有保留对它的引用,GC 就会认为你不在乎。

为了让我们的用户更清楚这一点,当在模拟器上以调试模式运行 MonoTouch 时(并且有一个命令行选项可以控制任何构建),我们在模拟器上添加了一个线程,该线程连续调用 GC.Collect() 每次几秒钟。这使得您可能没有保留对您的对话框的引用更加明显。

后来,我们发现一个非常有用和常见的模式是保留两种除了副作用之外真的没有用处的对话框:UIAlertView 和 UIActionSheet。我们更改了 MonoTouch,以便它在内部保留对这两个的引用,直到被解雇。

所以我们最终得到了两全其美的结果:在开发周期中,您可以捕获早期丢失的对所需对象的引用,并且我们处理了两种最常见的情况,它们仅对它们的副作用有用。

于 2011-08-19T02:21:13.607 回答
1

这是很多好问题。

关于攻击性,一旦不再引用对象,垃圾收集器就可以收集对象。如果它这样做很慢(称为被动),您可能永远不会注意到您的软件中存在的一些错误。

OTOH 在低内存条件下运行应用程序(多任务)带来了它自己的问题。因此,更频繁地收集(称之为积极)将更快回收内存并有助于整体性能。但是,如果在没有托管引用之后仍然使用对象,您更有可能遇到(您自己的)错误。

于 2011-08-18T20:08:34.303 回答
1

因此,在阅读了代码后,我找不到为什么会出现问题(并且没有足够的代码来快速尝试)。现在,如果崩溃与 UIButton 有关,那么 AddSubView 应该在逻辑上进行了引用。阅读文档确认情况确实如此(重点是我的):

要添加的视图。这个观点被接收者保留。添加后,此视图显示在任何其他子视图之上。

一些谷歌搜索让我发现了错误 #670294 ,它链接到一个与您链接的问题非常相似的 stackoverflow问题。评论 #22 描述了此问题的解决方法(这是一个错误),并在 MonoTouch 4.1 中得到修复。

现在我不能告诉你这是一个影响 MonoTouch 本身的 GC 问题(相同的规则适用于每个人)或无关。我它是相关的,因为保留另一个参考被引用为解决方案 -但由于我很好奇,我会查看修复并稍后添加评论;-)

于 2011-08-19T01:32:34.877 回答
0

我是那个说GC“更具侵略性”的人。这是我的术语-我认为Miguel对此的看法有所不同。我的解释是基于这样一个事实,即您可以在 MT3 中逃脱的事情在 MT4 中不再有效(或不那么可靠)。

于 2011-08-18T20:28:55.327 回答
0

另一个答案...

关于 iOS5:Apple 声称在 iOS5 中应用会收到一个内存警告,然后就会被杀死。与之前的任何其他版本不同,应用程序收到三个警告。这对 Monotouch 意味着什么?它将如何处理这种行为?

我不会谈论 iOS5(因为我不跟踪哪些是公开的,哪些不是)。由于您不知道内存可能有多低(或其他东西需要),因此使用非常复杂的策略来释放内存是没有意义的。用户在其他地方需要它,把它还给它:)

处理这个问题的方法是覆盖DidReceiveMemoryWarning并释放所有你可以的东西,比如:

  • 调用GC.Collect() - 这是为数不多的调用它的正确时机之一;
  • 清除您拥有的所有缓存(例如,下载的数据,如果需要,您可以稍后重新计算的任何其他内容)
于 2011-08-18T21:16:20.337 回答