我有一些代码将图像加载到OpenGL纹理中。在这个过程中,我最终加载了3个位图,因为我需要加载原始位图(适合显示尺寸)并根据EXIF数据重新定位位图。我很快就在每个位图上调用.recycle()
,但我注意到我的记忆似乎没有改变。
以下是内存监视器显示的内容:
正如您所看到的,在加载图像后我使用了大约60MB的内存。当我旋转稍微下降的设备然后重新启动。这让我觉得没有泄漏,因为记忆永远不会超过它。
当我单击内存分析器中的GC按钮时,我的内存占用量急剧下降到大约8 MB。这是有道理的,因为在此过程中创建的三个位图被回收,因此可以进行垃圾回收。然后你可以看到,当我再次旋转并重建活动时,内存会向右跳回来。
这是我的代码,向您展示为什么会创建如此多的位图以及何时回收这些位图。
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 :我可以相信垃圾收集器会在需要时将内存恢复吗?
另外,如果我们应该如此明智地回收我们的位图,为什么这么多Bitmap方法会说“新位图可能与源相同,或者可能已经制作了副本”。如果它是一个不同的对象,每次使用这些方法来回收位图时,我是否真的必须检查相等性?
问题2 :当使用位图创建方法时,可能会也可能不会返回相同的位图或副本,我是否需要检查源和输出相等性以回收源(如果它是副本)?
我尝试用MAT分析这个问题,在使用高峰时使用堆转储(应该是60 MB),但它只报告18.2 MB的使用情况并且看起来没什么异常。他们会以不同的方式阅读事物吗?
答案 0 :(得分:3)
问题1:我可以相信垃圾收集器会在需要时将内存恢复吗?
是。如果传入的引用被清除,垃圾收集器将在需要时占用内存(通常用于新的分配)。致电recycle()
并不能帮助您完成此过程,也不会让它更快发生。
存在recycle()
方法,因为在Android 3.0之前,Bitmap
个对象不计入堆中;因此,该方法有助于GC的帮助,因为它没有记录该堆内存的内存记录。在3.0+中,内存是针对堆进行跟踪的,因此不再需要这些额外的簿记。
问题2:当使用位图创建方法时,可能会或可能不会返回相同的位图或副本,如果它是副本,我是否需要检查源和输出相等性以回收源?
createBitmap()
方法将在以下情况下返回相同的对象:
x
和y
均为零width
和height
匹配来源宽度和高度由于看起来你正在传递变换矩阵,所以除非矩阵是出于某种原因的身份,否则你将始终获得副本。但同样,除非你仍然支持2.x版本,否则不需要recycle()
。