在 运行 内存不足之前,GC 运行 不应该在 Xamarin.Android 中自动进行吗?

Shouldn´t GC run automatically in Xamarin.Android before running out of memory?

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

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

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

然后我在mainactivity的OnResume方法中做了GC.Collect()(打开有问题的activity)。现在我可以看到内存正常上升和下降。您可以在屏幕截图中看到结果:

根据Xamarin docs

The GC will run when the minor heap has run out of memory for new allocations

但这实际上并没有发生

您可能想在 link 的 Helping the 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 可调用包装器 (ACW),Mono GC 不知道它有多大,因此它不知道调用垃圾收集器。据我所知,ACW 是一种实现 Android 接口的方法。

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

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

----

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

An instance of a Java.Lang.Object type or derived type is at least 20 bytes in size. Managed Callable Wrappers do not add additional instance members, so when you have a Android.Graphics.Bitmap instance that refers to a 10MB blob of memory, Xamarin.Android's GC won't know that – the GC will see a 20-byte object and will be unable to determine that it's linked to Android runtime-allocated objects that's keeping 10MB of memory alive.

这表明,无论对象是否设置为 null,您都应该仍然手动调用 Xamarin GC,如果是 allocating/deallocating 可能会消耗大量内存的可调用包装器。

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

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

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

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

Garbage collection and references C#