我正在测试android 3.1,大堆大小的选项,大约250M的可用内存。
每当我点击应用程序首选项中的“测试”按钮时,我都会设置以下代码:
float [][][]foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
bm.recycle();
bm = null;
foo = null;
我有足够的记忆 - 我可以毫无问题地按几下按钮。
但是,如果我一直按下按钮,最终(少于20次点击)它会以OutOfMemory消失。 [通常在android.graphics.Bitmap.nativeCreate(原生方法)]
没有其他事情发生 - 我永远不必离开PreferencesActivity。当我点击按钮时,还会显示一个小Toast,因此正在进行少量其他UI活动。
这是由于碎片,还是Android Bitmap代码和/或GC中的一个可怕的错误?或者我只是在做一些愚蠢的事情? (请让它成为愚蠢的东西......)
有人有解决方法吗?因为上面的代码完全代表了我的代码每次用户调用它时所要做的事情,而且现在尽管细致地清除了变量,但它在几次使用后就会消失。 (这已经让我疯了很久了!)
[更新]
我已经确认这是一个碎片问题或gc错误,因为堆转储显示我在闲置时没有使用5.6M(没有泄漏),在处理过程中大约26M达到峰值。 (此外,本机堆保持在4M以下。)虽然java堆同时在我的测试设备上一直增长到280M限制,此时我开始获得OutOfMemory异常。所以我在峰值时只使用了10%的可用堆,但是获得了OutOfMemory。
[添加对System.gc()的调用不幸修复了我上面给出的简单测试用例。我说不幸是因为(A)它不应该有所作为,(B)因为我已经在我的真实代码中定期调用它,所以这意味着我上面的简单测试用例太简单了。]
有没有其他人遇到这个?任何解决方法?有没有一种优雅的方式来重新启动我的应用程序?
[更新]
以下版本在3到4次调用中可靠地导致OutOfMemory(按下按钮):
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();
内存跟踪显示每次调用时堆都在稳步增长,直到达到限制并死亡。如果我删除三个分配中的任何一个,它就会达到平衡并无限期地存活下来。删除除最后一个gc()之外的所有gc()会导致它稍早死亡。
我会说这是一个碎片问题,而不是gc bug本身。如果有人知道如何解决它,请告诉我。 int []分配用于编写位图,因此我没有选择将其分配为2d数组(android Bitmap库的限制)。
答案 0 :(得分:4)
这是另一个SO页面,显然有解决此问题的方法:
Strange out of memory issue while loading an image to a Bitmap object
具体来说,以法莲的回答(摘录):
“1)每次执行BitmapFactory.decodeXYZ()时,请确保传入一个将inPurgeable设置为true的BitmapFactory.Options(并且最好将inInputShareable也设置为true)。
“2)永远不要使用Bitmap.createBitmap(width,height,Config.ARGB_8888)。我的意思是从来没有!我几乎没有通过几次没有引起内存错误。没有回收量(),System.gc (),无论有什么帮助。它总是引发异常。另一种实际工作方式是在你的drawables中使用虚拟图像(或者你使用上面的步骤1解码的另一个Bitmap),将其重新缩放到你想要的任何位置,然后操纵结果Bitmap(比如将它传递给Canvas以获得更多乐趣)。所以,你应该使用的是:Bitmap.createScaledBitmap(srcBitmap,width,height,false)。如果由于某种原因你必须使用暴力创建方法,然后至少通过Config.ARGB_4444。“
在评论中,有人说这解决了他们的问题,这与OP的问题非常相似。
我想补充一点,Diane Hackborn评论说,从3.0开始,Android不再从本机堆中分配位图,而是直接从常规堆中分配它们。这可能会使您的本机堆数字无关紧要。请参阅hackbod对此页面的评论:
我想这意味着Honeycomb关于位图分配的一个相当重大的变化,因此这可以解释为什么存在这种分配的错误(如果有的话)。我不知道这个改变对recycle()命令有什么影响,但根据Ephraim的上述评论,答案可能是“不是很好”。
最后,
使用largeHeap来摄取巨大的位图可能会被视为与其他应用程序不兼容,特别是如果你接近设备的物理极限。我不确定你怎么能避免这种情况,但是当你的应用程序在其他应用程序上执行时,请为许多onPause()/ onResume()活动做好准备,然后他们会退回到你的应用程序上。这个答案包括对此的讨论:
答案 1 :(得分:1)
为了防止碎片,你可以只分配大数组和Bitmap一次并重复使用它。
对于Android,有一些警告,因为Android试图在某种程度上管理你的应用程序的资源。例如,Activity
或View
可能会在不可见的情况下被卸载,如果它们再次可见则会重新运行。因此,大型事物最好由Application
个对象或static
个地方存储。
如果这只是用于某个首选项对话框,则应在第一次使用时保留它,但之后保留它,以便在每次运行时不使用那么多内存。如果很少使用它,您可能应该在保留首选项屏幕后重新启动应用程序。如果做得好,用户不需要注意它,你会再次获得一个新的和记忆友好的过程。
答案 2 :(得分:-2)
有一篇关于在android developer.android.com上管理位图内存的非常详细的文章:
http://developer.android.com/training/displaying-bitmaps/manage-memory.html
基本上他们建议使用Bitmap.recycle()以避免Android 2.3.3及更低版本的OutOfMemoryError错误。根据文档,它释放与Bitmap对象关联的本机对象。