2

我们正在实现一个似乎存在重大内存泄漏的应用程序。例如,我们有一个视图及其对应的视图模型,该视图模型在单分析器中注册了 38 次,但它应该被垃圾回收。我们有很多自定义控件等,但是应该在哪里处理这些 - 从 ios 6 开始不再调用 viewdidunload 那么我们应该在哪里进行清理?

问候

4

2 回答 2

5

这是一个很大的问题……对于一般情况,不容易回答。

一般来说,如果您编写了简单的 ViewModel 和简单的 View,那么您将不会遇到任何内存泄漏。

但是,如果您有引用 ViewModel 的 View,而后者又具有以某种方式引用 View 的回调,那么很可能会发生内存泄漏——尤其是当您的 View Model 订阅服务上的事件时。


一种特别糟糕的情况是 ObjC 和 C# 都引用了对象。在http://forums.xamarin.com/discussion/97/correct-way-to-pop-a-dialogviewcontroller-mine-are-staying-in-memory上对此进行了一些讨论,其中也提到了我们曾经遇到的问题SQL 位示例 - https://github.com/slodge/MvvmCross/issues/19

您当前的泄漏可能不是这种情况,但值得阅读 Rolf 的回答 - http://forums.xamarin.com/discussion/comment/535/#Comment_535 - 几次 - 这不是入门级解释,但它最终是有道理的!


因此,为了解决您当前的问题...

  1. 找出泄漏的内容

  2. 找出原因 - 是什么保留了参考资料。

  3. 修理它。

关键是在对 3 进行错误修复之前投入大量精力来研究 1 和 2。在不真正知道“它”是什么的情况下尝试“修复它”是没有意义的。

好消息是,Mono 分析器 - 具有用于识别哪些内容引用了哪些内容的内置工具 - 非常有助于完成这项工作。

根据您的描述,我知道您已经找到了这个工具 - 但对于其他阅读者,请参阅 - http://docs.xamarin.com/ios/Guides/Deployment%252c_Testing%252c_and_Metrics/Monotouch_Profiler


一旦您确定了泄漏的原因和原因,那么第 3 步将需要一些思考,但希望很容易回答。

有时解决方案是:

  • 只需修复一行错误的代码......哪一行是难点。
  • 使用“返回”检测来确定何时断开绑定或事件。
  • 使用 'willappear'、'willdisappear' 添加生命周期事件以更改您订阅/取消订阅事件的方式
  • 使用 C# 事件以外的替代方法 - 例如使用 TinyMessenger(或 MvvmCross 插件信使)之类的 Messenger - 这些具有通常使用WeakReference类来避免泄漏的优点。
  • 在“适当的时间”处理“某事”——再次解决“某事”和“适当的时间”是其中的难点

无论发生什么,不要惊慌,从工程的角度来解决这个问题。这些泄漏也发生在非 MvvmCross 和非 MonoTouch 代码中 - 使用 MvvmCross 和干净的 IoC 架构应该更容易找到和删除它们。


如果问题确实出在某处的 MvvmCross 绑定中,请务必将其记录为错误 - 我非常重视这些问题!

MvvmCross repo 上关于我们是否不应该对所有绑定代码使用 Wea​​kReferences 的长时间讨论中仍然存在一个未解决的错误 - 请参阅https://github.com/slodge/MvvmCross/issues/17 - 我已经考虑过这 - 它会帮助人们避免一些错误......但不是全部。这个问题仍然悬而未决。


更新:我没有回答

我们有很多自定义控件等,但是应该在哪里处理这些

框架应该为你处理这些。

如果没有,那可能是因为其他东西正在泄漏并保留在您的 View 上,而后者又保留在您的 Controls 上。您需要修复该潜在问题,而不是过早地调用控件上的 Dispose()。内存泄漏调试并不容易,但很有趣(有时)

于 2013-02-04T14:10:14.797 回答
1

一个好的规则是添加到基于 NSObject 的类的容器应该只引用使用 Wea​​kReference 对象的容器。

像这样:

 // MyView is a UIView, which is an NSObject, so the rule will apply here
 class MyView : UIView {
       WeakReference<UIViewController> myController;

       public MyView (RectangleF bounds, UIViewController myContainer) 
           : base (bounds) {
           this.myController = myContainer;
       }
 }
于 2013-02-06T16:42:11.810 回答