15

我正在为 Android Honeycomb 编写一个非常占用内存的应用程序,并且我一直非常小心recycle()未使用Bitmap的 s ;事实上,这对于应用程序的工作来说是必要的,因为Bitmaps 不断地循环进出内存。但是,我刚刚onConfigurationChanged()在.ActivityonStop()

目前我的onStop()方法:

  • 设置一些Views 以显示默认值Drawable
  • 调用recycle()这些Bitmaps 以前使用的Views;
  • 对 s 的引用无效Bitmap

不幸的是,使用 Eclipse 内存分析器,这似乎对内存使用没有任何影响

正如您所想象的那样,在以一种名义上的垃圾收集语言为释放资源付出了如此多的努力后,我希望能有更多的效果。所以我的问题是:做recycle()什么?它是否真的触发了垃圾收集,或者系统会保留内存——即使你调用了——System.gc()直到它觉得需要摆脱一些东西?

注意我知道Bitmaps 实际上并没有保存在常规堆中,但我认为调用recycle()足以确保它们从本机堆中删除。

部分答案

我发现如果 anImageView包含Bitmap已回收的 a ,则Bitmap数据仍保留在内存中,直到setImageBitmap(null)ImageView. 如果setImageResource(...)或被setImageDrawable(...)调用,甚至可能是这种情况(它们是加载在一个相对较小的九个补丁中 - 但是,MAT 分析表明这并没有删除Bitmap包含在私有成员中的大ImageView)。简单地调用这个函数onStop()已经从我们的应用程序的堆中剔除大约 10MB。不过,显然这可能不适用于 Android 的预蜂窝版本。

4

3 回答 3

6

正如贾斯汀所说,位图数据不在虚拟机堆中分配。在VM heap(很小)中有对其的引用,但实际数据是由底层Skia图形库在Native heap中分配的。[请注意,这可能在以后的 Android 级别中发生了变化,但在 2.1 和 2.2 中确实如此] 当您执行 recycle() 时,将 VM 堆中的一小部分和本机堆中的实际数据标记为免费且可用于GC。但实际的收集是由两种不同的 GC 机制执行的。VM 堆中的部分由 Davlik GC 收集 - 您可以通过 DDMS 看到发生的情况。但是本机堆数据是由 Skia GC 收集的,它似乎更懒惰(它运行的频率更低?)。这意味着,即使使用严格的 recycle()s,也有可能领先于原生堆 GC。幸运的是,有一些机制可以监视本机堆的状态。看BitmapFactory OOM 让我抓狂

于 2011-10-21T18:23:18.843 回答
6

我发现,从 Honeycomb 开始,如果 anImageView包含Bitmap已回收的 a,则Bitmap数据仍保留在内存中,直到setImageBitmap(null)在 ImageView 上调用。如果setImageResource(...)或被setImageDrawable(...)调用,甚至可能是这种情况(在这种情况下,一个非常大的位图被一个相当小的九个补丁替换,但只有setImageBitmap(null)在加载九个补丁之前被调用时才会实际释放内存)。

于 2011-10-24T10:18:52.147 回答
3

回收释放分配给位图的本机内存。实际的 Bitmap 对象将保留在 Dalvik Heap 中,直到下一次垃圾回收(但该对象占用的内存微不足道)。

据我所知,确实没有办法转储本机堆。因此,您将无法查看位图的本机数据是否通过堆转储消失了。但是,您应该会看到应用程序使用的内存总量减少了。这个问题应该可以帮助您发现访问应用程序的内存使用统计信息的各种方法。

于 2011-10-21T17:27:56.250 回答