1

更新——请原谅我在下面的冗长。尽可能简洁,它的行为是:

try {
    mArrowBitmap = BitmapFactory.decodeFile(nam);
} catch(OutOfMemoryError e) {
    Log.e(TAG, "OUT OF MEMORY ERROR!!! ["+e+"]");
}

这意味着当外部堆耗尽时它会抛出 OOME。我可以抓住它,并在单元测试中使用它。

然而,这行为不端:

try {
    mArrowDrawable = new BitmapDrawable(mContext.getResources(), mArrowBitmap);
} catch(OutOfMemoryError e) {
    Log.e(TAG, "OUT OF MEMORY ERROR!!! ["+e+"]");
}

这意味着它执行了一个非常令人印象深刻的 suppuku。那时我所能做的就是翻遍它的口袋寻找零钱。

对于那些有更多时间的人来说。. .

问题:我有很多位图,一些来自资源,一些从外部加载。我在设备上做了一些不可避免的操作(即我不能提前做的事情,或者做服务器端的事情)。在加载过程中的某个地方,我至少有一次内存泄漏。我正在追求这一点,并假装有能力(并且花费大量时间盯着 DDMS/MAT)。感谢对 SO 的大量评论,我至少对位图进行了基础研究,尤其是在蜂窝出现之前的位置。我的应用程序运行良好 Honeycomb 和转发。它在姜饼上运行得不太好。我可以

(a) 忽略内存泄漏,因为 Honeycomb 和 forward 最终将回收堆内存,而是尝试让地球上的每个人停止使用 Gingerbread,或者

(b) 隔离并消除内存泄漏。

选项(b)似乎更好。

在 Gingerbread 上,我了解我的位图(包括系统在我加载.xml或时神秘地为我创建的位图)的本机“支持”内存Drawables都位于 Dalvik 堆之外。我进一步理解,Dalvik 堆上唯一的东西是一个(相对)小的指向本机后备内存的指针。当我试图释放资源时,我必须找到我创建的所有位图,并对它们进行同步recycle。我的方案,fwiw,是在我创建它们时将我所有的位图“注册”到一个简单的向量中,然后迭代向量以在本机后备内存中回收任何类似于位图的东西。

出于这个原因,我对来自 Dalvik 堆的各种报告表示手头有大量内存,但我的decode调用因内存不足而失败,我并不感到不安。事实上,我已经将我的一些单元测试活动用于将边界推向边缘,以验证我没有行为不端(并且希望将来不要这样做)。我使用“标准”Android 单元测试类进行这些单元测试,因为 Robolectric 无法“看到”我上面提到的堆。忏悔:我真的更喜欢 Robolectric,因为它的速度快了无数倍。

到达这里还有很长的路要走:

当我通过创建太多位图故意运行本机“支持”内存时,大多数时候,我得到了我的期望:OutOfMemoryError. 我抓住了那个错误并负责任地采取行动(对于非常小的“负责任”值)。

当我胜过Drawable调用时(而不是BitmapFactory调用,但有时两者都这样做),而不是错误或异常,我在logcat:

11-17 16:22:39.372: I/dalvikvm-heap(15069): Clamp target GC heap from 33.916MB to 32.000MB
11-17 16:22:39.372: D/dalvikvm(15069): GC_CONCURRENT freed 5K, 39% free 3701K/6023K, external 26854K/27965K, paused 2ms+2ms
11-17 16:22:39.402: D/dalvikvm(15069): GC_EXTERNAL_ALLOC freed 5K, 39% free 3696K/6023K, external 26854K/27965K, paused 36ms
11-17 16:22:39.442: E/dalvikvm-heap(15069): 81796-byte external allocation too large for this process.
11-17 16:22:39.442: E/dalvikvm(15069): Out of memory: Heap Size=6023KB, Allocated=3696KB, Bitmap Size=26854KB, Limit=32768KB
11-17 16:22:39.442: E/dalvikvm(15069): Trim info: Footprint=6023KB, Allowed Footprint=6023KB, Trimmed=404KB
11-17 16:22:39.442: E/GraphicsJNI(15069): VM won't let us allocate 81796 bytes
11-17 16:22:39.462: I/dalvikvm-heap(15069): Clamp target GC heap from 33.912MB to 32.000MB
11-17 16:22:39.462: D/dalvikvm(15069): GC_CONCURRENT freed <1K, 39% free 3696K/6023K, external 26854K/27965K, paused 3ms+2ms

我摸索着夹紧零件。我似乎无法解开的是如何检测中间的部分:

11-17 16:22:39.442: E/dalvikvm(15069): Out of memory: Heap Size=6023KB, Allocated=3696KB, Bitmap Size=26854KB, Limit=32768KB

当然,这似乎不是一个Error或一个Exception. 我可以通过观看 DDMS 手动查看这种不良行为。但是我不知道如何以编程方式隔离它,以便我可以将它合并到我的单元测试中。当然,在我的应用程序中捕捉到这种行为也会很好,这样如果一个错误确实滑过了我的单元测试挑战(它发生(经常发生)),我可能会避免应用程序毫不客气地吐槽它的鞋子。

非常感谢这里的热心人士,他们泰然自若地解释了 Android 内存的奥秘。对于仍在阅读的任何人,并且像我一样对 Android 有趣的内存结构感到困惑,我衷心推荐从这里开始,从Dubroy 先生的出色演示开始——非常值得一看,尤其是在观众提问的最后。最后是一个离机的人,他就这些同样令人费解的记忆位提出了一些非常见多识广的问题。

我们将不胜感激地接受这里的任何指导。

4

0 回答 0