【发布时间】:2014-11-06 01:21:06
【问题描述】:
我有一些代码将图像加载到 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 的使用情况,并没有什么异常。他们的阅读方式会有所不同吗?
【问题讨论】:
-
“这让我认为没有泄漏”——我建议您使用 MAT,而不是猜测。 “如果我们应该如此明智地回收我们的位图”- 在现代版本的 Android 上,您应该通过
BitmapFactory.Options上的inBitmap来重用您的位图。recycle()有点小技巧,主要针对 Android 1.x/2.x,以帮助 GC。引用当前的Bitmap源,“这是一个高级调用,通常不需要调用,因为当没有更多对该位图的引用时,正常的 GC 进程将释放此内存”。 -
现在,在您的情况下,您可能不需要重用位图,这很好。如果 MAT 表明您的位图没有被强保留,它们最终将被 GC'd。这种情况发生的速度取决于多种因素,但如果没有其他因素,如果尝试分配某些内容失败,则会出现
GC_FOR_ALLOC,这将收集所有可能的垃圾。 -
Re: 重用位图,我正在使用采用源位图的位图静态工厂方法,我想知道它与选项中的 inBitmap 相比如何。我也没有理由保留位图,因为我只是使用它们传递给 OpenGL,然后它们就消失了,直到我必须重新初始化视图(通过旋转等)。
-
MAT 堆中有多少是位图内存?如果您在 2.x 设备上运行该跟踪,则位图内存不会显示在 MAT 堆下。否则,差异可能只是在 MM 报告堆大小信息和 MAT 报告实际对象大小之间。
-
@Devunwired 最大的消费者(4.4 MB)实际上是
com.android.content.res.Resources。然后我们进入java.lang.reflect.ArtMethod。鉴于我在屏幕上显示的视图(来自资源的 ImageViews),这一切都是有道理的。 MAT 中报告的分配比我预期的要多,奇怪的是,当 MM 明显被成功收集时,它显示的更多。
标签: android memory memory-leaks bitmap garbage-collection