不应该在Xamarin.Android在内存耗尽之前自动运行GC? [英] Shouldn´t GC run automatically in Xamarin.Android before running out of memory?

查看:143
本文介绍了不应该在Xamarin.Android在内存耗尽之前自动运行GC?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



在每次打开活动时,我都看到Xamarin Profiler内存不断增加: .pngrel =nofollow noreferrer>



我确定没有任何属性或事件处理程序可能会停留在该活动中。我甚至删除了每个图像,按钮等,试图检测是什么导致了内存泄漏。还是一样的......



然后我在中加入了 GC.Collect()主要活动的OnResume 方法(打开有问题的活动的方法)。现在我可以看到内存应该如何上下移动。你可以在截图中看到结果:





按照 Xamarin文档


当小堆用完新分配时,GC将运行


但实际上并未发生

解决方案

您可能需要在链接下进一步阅读帮助GC
GC有一个不完整的进程视图,当内存不足时可能无法运行,因为GC不知道内存不足。
Managed Callable Wrappers不会添加额外的实例成员



基本上,它会出现BaseActivity是一个Android Callable Wrapper(ACW)和Mono GC不知道它有多大,所以它不知道调用垃圾收集器。从我所收集的内容来看,ACW是一种实现Android接口的方式。



正如您发现的那样,解决方案是手动调用Xamarin中推荐的垃圾收集器docs when using ACW's。



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 ,您都应该 手动调用Xamarin GC如果您正在分配/取消分配可能消耗大量内存的Callable Wrappers。


$ b 在假设Java Object 是20个字节,如果分配的是100个对象,每个对象需要10MB,Xamarin GC相信4000字节的内存正在使用。实际上,〜1GB正在使用中,并且GC可能会或可能不会被调用。

I spent almost a whole day trying to find out the reason of a memory leak in Android. There´s an activity that I open/close many many times (with a timer). After a while I was getting OutOfMemory errors:

I saw the memory going up constantly in Xamarin Profiler every time the activity opened:

I made sure there were no properties or event handlers that could be stuck in that activity. I even removed every image, buttons, etc, trying to detect what was causing the memory leak. Still the same...

Then I did GC.Collect() in the OnResume method of main activity (the one that opens the problematic activity). Now I can see the memory going up and down as it should. You can see the result in the screenshot:

As per Xamarin docs:

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

But that is not actually happening

解决方案

You may want to read a bit further down in your link under 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. and Managed Callable Wrappers do not add additional instance members

Basically, it would appear BaseActivity is an Android Callable Wrapper (ACW) and the Mono GC doesn't know how big it is, so it doesn't know to invoke the garbage collector. From what I gather, the ACW is a way to implement Android interfaces.

The solution is, as you discovered, to manually call the garbage collector which is recommended in the Xamarin docs when using ACW's.

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

----

Since the original posting of this answer, the Xamarin docs have improved in their explanation of this situation:

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.

This indicates that, regardless of whether objects are set to null or not, you should still manually call the Xamarin GC if you're allocating/deallocating Callable Wrappers that can potentially consume a large amount of memory.

Operating under the assumption a Java Object is 20 bytes, if one were to allocate and null 100 objects that consume 10MB each, the Xamarin GC believes that 4000 bytes of memory are in use. In reality, ~1GB is in use, and the GC may or may not be invoked.

这篇关于不应该在Xamarin.Android在内存耗尽之前自动运行GC?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆