android - 在调用 Bitmap.recycle() 之后我应该信任垃圾收集器吗?

标签 android memory memory-leaks bitmap garbage-collection

我有一些代码可以将图像加载到 OpenGL 纹理中。在此过程中,我最终加载了 3 个位图,因为我需要加载原始位图(大小适合显示)并根据 EXIF 数据重新定向位图。我在每个位图上快速调用 .recycle(),但我注意到我的内存似乎没有改变。

这是内存监视器显示的内容:

memory monitor

如您所见,加载图像后我使用了大约 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 的使用量,而且看起来没有什么异常。他们会不会有不同的解读方式?

enter image description here

最佳答案

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() 方法将返回相同的对象:

  • 源是不可变的
  • xy 都是零
  • widthheight 匹配源宽高
  • 没有应用任何转换矩阵

因为看起来您正在传递一个转换矩阵,所以您总是会得到一个副本,除非该矩阵出于某种原因是相同的。但同样,除非您仍然支持 2.x 版本,否则没有真正需要 recycle()

关于android - 在调用 Bitmap.recycle() 之后我应该信任垃圾收集器吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26770209/

相关文章:

java - 更新 ionic 框架后 Classes.dex 文件大小增加

linux - 修补/替换内存中的linux内核

c - (C) 使用数组进行动态内存分配

c++11 - 使用 valgrind Massif 工具,未创建结果文件

c++ - 创建本地 opencv mat 对象时内存泄漏

android - Android Studio 中的 Gstreamer 示例

android - 我可以在 sqlite3 中用转义序列声明表名吗?

java - Http URL 连接无法处理重定向

java - 加载到内存中的文件比磁盘上的文件大

objective-c - Objective-C : Potential Memory Leak in code