在启用 largeHeap
选项之前,我正在处理大型位图,它几乎消耗了应用程序可用的全部内存,并通过导航回收它并加载新的内存,几乎在整个可用堆上工作。但是,当某些操作需要更多内存时,应用程序会崩溃。所以我启用了 largeHeap=true
以获得更多内存。
但是这样做有一个意想不到的行为,看起来位图的 recycle()
方法大部分时间都不起作用,并且在 58Mb 内存中工作的应用程序(有时超过抛出OutOfMemoryException
) 现在以指数方式消耗内存并保持增长(目前我所做的测试达到 231Mb 分配内存),预期的行为是内存管理保持工作并且应用程序不会使用超过 60Mb。
我怎样才能避免这种情况?还是有效地回收位图?
编辑:实际上,当在设备上分配超过 390Mb 的内存时,我让它给出一个 OutOfMemoryError
。
阅读 GC_* 日志显示只有 GC_FOR_ALLOC 有时释放了 3.8Mb,但几乎没有其他 GC 运行释放了一些东西。
最佳答案
你应该看看Displaying Bitmaps Efficiently其中包括几种有效处理大型位图的方法,
- 高效加载大型位图
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth;
这将在下载之前为您提供图像的大小,在此基础上您可以检查设备的大小并使用 calculateInSampleSize()
和 decodeSampledBitmapFromResource()
在文档的解释中给出。
计算我们需要将图像缩放多少,
if (imageHeight > reqHeight || imageWidth > reqWidth) { if (imageWidth > imageHeight ) { inSampleSize = Math.round((float)imageHeight / (float)reqHeight); } else { inSampleSize = Math.round((float)imageWidth / (float)reqWidth); } }
int inSampleSize = Math.min(imageWidth / reqWidth,imageHeight / reqHeight);
你可以设置inSampleSize
,
options.inSampleSize = inSampleSize;
最后一定要打电话,
options.inJustDecodeBounds = false;
否则它将返回 Bitmap 作为 null
脱离 UI 线程处理位图
在 UI 线程上处理位图从来都不安全,因此最好在后台线程中执行此操作并在处理完成后更新 UI。
缓存位图
LruCache可从 API 12 获得,但如果您有兴趣使用以下版本,它也可在 Support Library 中获得也。因此,应该使用它有效地缓存图像。您也可以使用 DiskLruCache对于您希望在外部存储中保留更长时间的图像。
清除缓存
有时,当您的图片太大时,即使缓存图片也会导致
OutOfMemoryError
,因此在这种情况下,最好在图片超出范围或长时间不使用时清除缓存,这样可以缓存其他图像。我已经为此创建了一个演示示例,您可以从here 下载
关于android - 启用 largeHeap 的位图回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12716574/