【问题标题】:What does it mean if the garbage collector is "more aggressive" in Monotouch 4?如果垃圾收集器在 Monotouch 4 中“更具侵略性”,这意味着什么?
【发布时间】:2011-08-19 10:21:13
【问题描述】:

我偶然发现了这个问题:Button in ContentView causes crash in MonoTouch runtime. Bug in Monotouch 4.0? 并且询问者对 Monotouch 的“更具侵略性”的垃圾收集器有问题。

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

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

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

【问题讨论】:

    标签: .net mono garbage-collection xamarin.ios boehm-gc


    【解决方案1】:

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

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

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

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

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

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

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

    【讨论】:

    • 你能指出我引用的示例中收集了什么吗?是代表消失了吗?因为单元格在屏幕上,所以按钮在单元格中,并且按钮分配了一个代表 - 可能会收集什么?
    【解决方案2】:

    这是很多好问题。

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

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

    【讨论】:

    • 但是,如果我们提出询问者的问题:那里有什么问题?为什么不能不调用他的事件处理程序?单元格在那里,按钮在单元格中,并且按钮有一个处理程序。为什么要收集任何东西?
    • 老实说,我不知道从 GC 的角度来看,对象分配了处理程序/委托这一事实是否应该算作活动引用?这样做可能会产生意想不到的后果。我很想听听 Xamarin 对这个想法的看法。
    • 反之亦然。无法再找到您的处理程序/代表。该按钮仍然存在,我假设您可以在您的 UI 中看到它。但这并没有使它更清楚。但是,是的,我想听听 Xamarin 关于这个。
    • 只回答部分原始问题是有原因的 ;-) 我会在有时间时尝试回答其他问题(包括阅读链接的源代码)。但我的观点是:垃圾收集频率的变化会暴露/隐藏应用程序中的错误。
    • 委托是对对象方法的引用,所以是的,它是一个活动引用。参考是一种方式。从持有对委托中引用的对象的引用的那个。因此,从按钮向 TouchUpInside 事件添加委托不会使按钮保持活动状态。该按钮确实使委托中的对象保持活动状态。一旦按钮不再被引用,它可能会被 GCed。见stackoverflow.com/questions/298261/…
    【解决方案3】:

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

    要添加的视图。 此视图由接收方保留。添加后,此视图显示在任何其他子视图之上。

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 我仍然看不出您的示例代码有什么问题。
      • FWIW 我自己喜欢“激进”一词 :-) 就像“在 MT3 中逍遥法外”是另一个好词一样。但是我不喜欢“不那么可靠”,因为我们应该尽最大努力从不依赖这种行为。就像忽略线程问题一样,这种情况以后总会回来困扰你;-)
      【解决方案5】:

      另一个答案...

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

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

      解决这个问题的方法是覆盖 DidReceiveMemoryWarning 并释放 一切 你可以,例如:

      • 致电GC.Collect() - 这是为数不多的电话之一;
      • 清除您拥有的所有缓存(例如下载的数据,如果需要,您可以在以后重新计算的任何其他内容)

      【讨论】:

      • 我认为如果 DidReceivememoryWarning 触发,GC.Collect 会自动调用。至少我真的希望它。
      猜你喜欢
      • 2012-04-02
      • 1970-01-01
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-10
      • 1970-01-01
      • 2019-05-15
      相关资源
      最近更新 更多