在 运行 内存不足之前,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#
我花了将近一整天的时间试图找出 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#