我有一些代码可以将图像加载到 OpenGL 纹理中。在此过程中,我最终加载了 3 个位图,因为我需要加载原始位图(大小适合显示)并根据 EXIF 数据重新定向位图。我在每个位图上快速调用 .recycle()
,但我注意到我的内存似乎没有改变。
这是内存监视器显示的内容:
如您所见,加载图像后我使用了大约 60MB 的内存。当我旋转设备时,它会稍微掉落然后又会恢复原状。这让我认为没有泄漏,因为内存永远不会超过那个。
当我单击内存分析器中的 GC 按钮时,我的内存占用量急剧下降到 8 MB 左右。这是有道理的,因为在此过程中创建的三个位图被回收,因此可以被垃圾收集。然后你可以看到,当我再次旋转并重建 Activity 时,内存会立即跳回。
这是我的代码,用于向您展示为什么创建了这么多位图以及它们何时被回收。
void layoutImage() {
...
Bitmap bitmap = loadOrientedConstrainedBitmapWithBackouts(...);
imageTexture = new GLTexture(bitmap);
bitmap.recycle(); // recycle bitmap 2
}
Bitmap loadOrientedConstrainedBitmapWithBackouts(Context context, Uri uri, int maxSize) {
...
Bitmap bitmap = loadBitmapWithBackouts(context, uri, sampleSize); // create bitmap 1
...
Bitmap out = orientBitmap(bitmap, orientation); // create bitmap 2
bitmap.recycle(); // recycle bitmap 1
return out;
}
Bitmap orientBitmap(Bitmap source, int orientation) {
...
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight, matrix, true); // create bitmap 3
}
我不确定这是个问题,可以这么说,因为内存没有攀升(所以没有泄漏),但我很好奇它什么时候保持这么高。由于强制垃圾收集可以很好地清除它,我是否应该假设如果系统需要该内存,它将在下一次 GC 传递时收集?它在我写这篇文章的整个过程中一直在运行,并且仍然舒适地坐在 60 MB。
问题 1:我能否相信垃圾收集器会在需要时回收该内存?
此外,如果我们应该如此明智地回收我们的位图,为什么那么多位图方法会说“新位图可能与源是同一对象,或者可能已经制作了副本”之类的话。如果位图是不同的对象,我每次使用这些方法回收位图时真的必须检查相等性吗?
问题 2:当使用位图创建方法时,可能会或可能不会返回相同的位图或副本,如果它是副本,我是否需要检查源和输出是否相等以回收源?
编辑:
我曾尝试使用 MAT 分析这个问题,在使用高峰期(应该是 60 MB)使用堆转储,但它只报告了 18.2 MB 的使用量,而且看起来没有什么异常。他们会不会有不同的解读方式?
最佳答案
Question 1: Can I just trust that the garbage collector will take that memory back if needed?
是的。如果传入引用被清除,垃圾收集器将在需要时占用内存(通常用于新分配)。调用 recycle()
不会帮助这个过程,也不会让它更快地发生。
recycle()
方法的存在是因为 Bitmap
对象直到 Android 3.0 才计入堆;因此该方法有助于辅助 GC,因为它没有其他方式记录该内存计入其堆。在 3.0+ 中,内存是根据堆进行跟踪的,因此不再需要这种额外的簿记。
Question 2: When using Bitmap creation methods, that may or may not return the same bitmap or a copy, do I need to check source and output equality to recycle the source if it's a copy?
如果满足以下条件,createBitmap()
方法将返回相同的对象:
- 源是不可变的
x
和y
都是零width
和height
匹配源宽高- 没有应用任何转换矩阵
因为看起来您正在传递一个转换矩阵,所以您总是会得到一个副本,除非该矩阵出于某种原因是相同的。但同样,除非您仍然支持 2.x 版本,否则没有真正需要 recycle()
。
关于android - 在调用 Bitmap.recycle() 之后我应该信任垃圾收集器吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26770209/