Android GC内存碎片化失败。解决办法?

12 浏览
0 Comments

Android GC内存碎片化失败。解决办法?

我正在测试Android 3.1上的大堆大小选项,大约有250兆的可用内存。\n我设置了以下代码,每当我在应用的偏好设置中点击测试按钮时,它就会运行:\n

float [][][] foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
bm.recycle();
bm  = null;
foo = null;

\n对于这个任务,我有足够的内存 - 我可以多次点击按钮而没有问题。\n但是,如果我不断点击按钮,最终(不到20次点击)会出现OutOfMemory错误。[通常是在android.graphics.Bitmap.nativeCreate(Native Method)中]\n除此之外没有其他操作 - 我从未离开PreferencesActivity。当我点击按钮时还会显示一个小的Toast提示,因此还有一小部分其他UI活动。\n这是由于碎片化还是Android位图代码和/或GC中的一个严重错误导致的?还是我做了一些愚蠢的事?(请让它是一些愚蠢的东西......)\n是否有人有解决方法?因为上述代码几乎代表了每次用户调用它时我的代码所必须执行的操作,而现在尽管我仔细清除变量,但在几次使用后它就会崩溃。(这已经让我抓狂了很长时间!)\n[更新]\n通过堆转储,我已经确认这是一个碎片化问题或GC错误,因为当闲置时我仅使用5.6兆内存(没有泄漏),在处理过程中峰值约为26兆。(此外,本机堆保持在4兆以下。)与此同时,Java堆增加到了我测试设备的280兆限制,此时开始出现OutOfMemory异常。因此,我只使用了峰值可用堆的10%,但是还是出现了OutOfMemory。\n[在上面提供的简单测试用例中添加一个System.gc()调用不幸地修复了该问题。我说不幸是因为(A)它不应该有任何影响,(B)因为我已经在我的真实代码中定期调用它,所以这意味着我上面的简单测试用例太简单了。]\n还有其他人遇到这个问题吗?有什么解决方法吗?有没有优雅的方法来重新启动我的应用程序?\n[更新]\n以下版本在3到4次调用(按钮按下)时可靠地导致OutOfMemory:\n

float [][][] foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
int [] bar = new int[3*2048*2048];
bm.recycle();
bm = null;
System.gc();
foo = null;
System.gc();
bar = null;
System.gc();

\n内存追踪显示,堆在每次调用时稳步增长,直到达到限制并崩溃。如果我删除其中一个三个分配之一,它会达到平衡并永远存活。删除除最后一个gc()之外的所有gc()会导致它稍微早些时候崩溃。\n我认为这是一个碎片化问题,而不是一个GC错误。如果有人知道如何解决,请告诉我。int []分配用于写入位图,因此我不能将其分配为2D数组(这是Android位图库的限制)。

0
0 Comments

在Android开发者网站上有一篇关于管理Android位图内存的非常详细的文章。基本上,他们建议在Android 2.3.3及更低版本中使用Bitmap.recycle()来避免OutOfMemoryError错误。根据文档,这个方法可以释放与Bitmap对象关联的本地对象。作者正在使用3.1版本,不再需要直接调用Bitmap.recycle()。

在这篇文章中,作者遇到了一个名为"Android GC memory fragmentation fail"的问题,这篇文章的目的是提供解决这个问题的方法。

问题的原因是当Android系统中的垃圾回收(GC)机制发生内存碎片化时,导致内存管理出现问题。内存碎片化是指内存中存在许多零散的小块空闲内存,但无法满足较大的内存需求。

解决这个问题的方法是使用以下代码片段来手动执行垃圾回收:

System.gc();
Runtime.getRuntime().gc();

这段代码会强制进行垃圾回收,帮助释放内存碎片,并提高内存利用率。

此外,作者还建议使用更高效的内存管理技术,例如使用图片压缩和缓存来减少内存占用。这些技术可以通过阅读Android开发者网站上关于管理位图内存的文章来了解。

总之,通过手动执行垃圾回收和使用更高效的内存管理技术,可以解决"Android GC memory fragmentation fail"问题,提高Android应用程序的性能和稳定性。

0
0 Comments

Android GC内存碎片化失败。解决方案?

为了防止碎片化,您可以只分配一次大数组和位图,然后重复使用它们。

对于Android来说,这有一些注意事项,因为Android会在一定程度上管理您的应用程序资源。例如,如果Activity或View不可见,可能会被卸载,并在再次可见时重新运行。因此,最好将大的东西存储在Application对象或静态位置上。

如果这只是用于一些偏好设置对话框,您应该在第一次使用时保留它,但之后保留它,以免在每次运行时使用太多内存。如果很少使用它,您可能应该在偏好设置屏幕离开后重新启动应用程序。如果做得好,用户不需要注意到它,并且您将获得一个新的、友好的内存进程。

不幸的是,这不是一个选择。这是一个图像处理应用程序,它接受用户提供的各种大小的图像(没有硬性最大值 - 最大值是可以适应可用内存的任何值)。

即使没有静态数组和位图,您仍然可以尝试在一个或多个图像后重新启动应用程序。也许只需通过finish()退出最后一个Activity,然后通过startActivity重新打开它。然而,虚拟机可能以一种“智能”的方式重用,因此可能需要在退出时运行一个辅助服务,再次启动您的主Activity。

2016年,内存碎片化问题仍然存在。我最初使用LruCache,但在使用了几个月后,我发现它导致了OutOfMemory错误,原因是内存碎片化。请参见https://github.com/andstatus/andstatus/issues/351。我现在想尝试的唯一解决方案是只分配一次图像缓存,然后重复使用缓存的位图内存。为了可重用,我将不得不分配最大尺寸的位图...

0
0 Comments

Android GC内存碎片化失败。解决方法?

在这个问题中,有一个似乎有解决方法的SO页面:Strange out of memory issue while loading an image to a Bitmap object

具体来说,Ephraim的回答如下(摘录):

“1)每次使用BitmapFactory.decodeXYZ()时,确保传入一个设置了inPurgeable为true的BitmapFactory.Options(最好还设置了inInputShareable为true)。

“2)绝对不要使用Bitmap.createBitmap(width, height, Config.ARGB_8888)。我是说绝对不要!我从来没有遇到过这个方法在几次尝试后不报内存错误的情况。无论怎样使用recycle()、System.gc(),都无济于事。它总是会引发异常。唯一另外一个可行的方法是在drawables中有一个虚拟图像(或者另一个使用步骤1解码的Bitmap),将其缩放到所需尺寸,然后对生成的Bitmap进行操作(例如将其传递给Canvas进行更多操作)。因此,你应该使用以下方法:Bitmap.createScaledBitmap(srcBitmap, width, height, false)。如果由于某种原因你必须使用强制创建方法,那么至少要传入Config.ARGB_4444。”

在评论中,有些人表示这个方法解决了他们的问题,这与这里的问题非常相似。

我想补充一点,Diane Hackborn在3.0 Android中评论说,Android不再从本地堆中分配位图,而是直接从常规堆中分配。这可能使你的本地堆数据无关紧要。请参见此页面上hackbod的评论:Bitmaps in Android

我猜这意味着从Honeycomb开始关于位图分配有了相当大的改变,所以这可能解释了为什么这样的分配存在问题(如果有的话)。我不知道这个改变对recycle()命令有什么影响,但根据Ephraim的上述评论,答案可能是“效果不好”。

最后,

使用largeHeap来加载大型位图可能被视为与其他应用程序不友好,特别是如果你接近设备的物理极限。我不确定如何避免这种情况,但要准备好频繁调用onPause() / onResume(),因为你的应用程序会影响其他应用程序,而它们也会影响你的应用程序。这个SO回答包括了对此的讨论:Detect application heap size in Android

inPurgeable现在已被弃用并被忽略。

0