【问题标题】:Shouldn´t GC run automatically in Xamarin.Android before running out of memory?在内存不足之前,GC 不应该在 Xamarin.Android 中自动运行吗?
【发布时间】:2015-12-26 19:12:07
【问题描述】:

我花了将近一整天的时间试图找出 Android 内存泄漏的原因。有一个活动我打开/关闭很多次(使用计时器)。过了一会儿,我收到了 OutOfMemory 错误:

每次活动打开时,我都看到 Xamarin Profiler 中的内存不断增加:

我确保没有可能卡在该活动中的属性或事件处理程序。我什至删除了每个图像、按钮等,试图检测导致内存泄漏的原因。还是一样……

然后我在主要活动的OnResume方法中做了GC.Collect()(打开有问题的活动的那个)。现在我可以看到内存按照它应该的方式上下波动。您可以在屏幕截图中看到结果:

根据Xamarin docs

当次要堆内存不足时,GC 将运行以进行新分配

但这实际上并没有发生

【问题讨论】:

标签: android memory-leaks xamarin garbage-collection xamarin.android


【解决方案1】:

您可能希望在帮助 GC 下的链接中进一步阅读: The GC has an incomplete view of the process and may not run when memory is low because the GC doesn't know that memory is low.Managed Callable Wrappers do not add additional instance members

基本上,看起来 BaseActivity 是一个 Android Callable Wrapper (ACW),而 Mono GC 不知道它有多大,因此它不知道调用垃圾收集器。据我所知,ACW 是一种实现 Android 接口的方式。

正如您所发现的,解决方案是在使用 ACW 时手动调用 Xamarin 文档中推荐的垃圾收集器。

http://developer.xamarin.com/guides/android/advanced_topics/garbage_collection/

----

自从最初发布此答案以来,Xamarin 文档对这种情况的解释有所改进:

Java.Lang.Object 类型或派生类型的实例是 至少 20 字节大小。托管的可调用包装器不添加额外的实例 成员,所以当你有一个 Android.Graphics.Bitmap 实例时 指的是 10MB 的内存,Xamarin.Android 的 GC 不会知道 – GC 将看到一个 20 字节的对象并且无法确定 它与保持的 Android 运行时分配的对象相关联 10MB 内存。

这表明,无论对象是否设置为 null,如果您正在分配/释放 Callable Wrapper,您应该仍然手动调用 Xamarin GC可能会消耗大量内存。

在假设 Java Object 为 20 字节的情况下运行,如果要分配和空 100 个对象,每个对象消耗 10MB,Xamarin GC 认为 4000 字节的内存正在使用中。实际上,大约 1GB 正在使用中,可能会或可能不会调用 GC。

【讨论】:

    【解决方案2】:

    调用垃圾回收并不能确保垃圾回收会运行或所有内存分配都会发生。很多时候它是关于删除对对象的引用。如果一个对象有对它的引用,它就不会被垃圾回收。我不得不以艰难的方式学习这一点。基本上要在任何时候解决这个问题,您可以随时清空一个对象,并在需要时设置它。示例:

    CustomObject cusObj = null;
    if (cusObj == null) 
    {
        cusObj = new CustomObject();
    }
    

    只需确保将对象清空即可删除引用。但如上面的答案所述,您也可以收集垃圾。请记住,GC 不会垃圾收集带有引用的项目。 看看:

    Garbage collection and references C#

    【讨论】:

    • 正如您在问题中看到的那样,这不是参考问题,因为我确保清理了所有内容
    • 不是真的,堆空间错误的最大原因是引用了不允许垃圾收集器在那里工作的对象。
    • 清空你的对象以摆脱引用本来可以解决问题。
    • 再一次,如果你仔细阅读问题和接受的答案,你会意识到在这种情况下问题来自于 Mono 没有发布 Android Callable Wrappers。是否将每个引用都归零也没关系。在您显式调用 GC 之前,该问题将一直存在
    • 这个问题是特定于 Xamarin.Android 的域;该信息实际上是正确的,但 xleons 原始问题非常具体到 monodroid 的实现细节。这个答案没有考虑 monodroid 实现的桥接机制,以确保 Java 和 .NET 对象的生命周期始终相同。
    猜你喜欢
    • 2014-10-04
    • 2014-09-19
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多