我正在测试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;
Run Code Online (Sandbox Code Playgroud)
我有足够的记忆 - 我可以毫无问题地按几下按钮.
但是,如果我一直按下按钮,最终(少于20次点击)它会以OutOfMemory消失.[通常在android.graphics.Bitmap.nativeCreate(Native Method)中]
没有其他事情发生 - 我永远不必离开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();
Run Code Online (Sandbox Code Playgroud)
内存跟踪显示堆在每次调用时稳定增长,直到达到限制并死亡.如果我删除三个分配中的任何一个,它就会达到平衡并无限期地存活下来.删除除最后一个gc()之外的所有gc()会导致它稍早死亡.
我会说这是一个碎片问题,而不是gc bug本身.如果有人知道如何解决它,请告诉我.int []分配用于编写位图,因此我没有选择将其分配为2d数组(android Bitmap库的限制).
请注意我没有内存泄漏.我的问题是一个更微妙的问题.
我最近写了一个Android应用程序,它进行图像处理.图像作为位图加载,然后以像素复制,以使用大量内存的方式处理(考虑浮点表示和填充中的傅里叶变换),然后转换回位图并保存.
问题是,至少通过android OS 2.3,总内存限制(通常为16MB)是组合java和(外部存储)位图,并且即使在内存中,java高水位标记也不会下降(我可以辨别)是免费的(成功GC'd),这意味着当我去分配最终的位图时,我经常"内存不足",即使到那时我已经释放了(和GC'd)大部分空间.即,我从来不需要一次完整的16MB,但是Bitmaps留下的空间似乎是16MB减去MAX历史java堆的使用量(与当前使用情况相反).
我看了一个Android开发人员关于内存问题的技术演讲,他暗示这个问题已经在操作系统的后续版本中得到修复(他们将Bitmap内存移动到java堆空间中),但与此同时大多数人都希望使用我的应用正在运行2.2或2.3.
长话短说,我想知道java堆是否曾被压缩(实际上是去碎片),以便高水位标记缩小(如果是这样,如何实现它)?
如果没有,那么有人有另一个建议如何处理这个问题?