本文介绍了启用 largeHeap 的位图回收的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在启用 largeHeap 选项之前,我正在处理大型位图,它几乎消耗了应用程序可用的全部内存,并通过导航和加载新内存来回收它,几乎可以在整个可用堆上工作.但是,当某些操作需要更多内存时,应用程序就会崩溃.所以我启用了 largeHeap=true 以获得更多内存.

但是这样做有一个意想不到的行为,看起来位图的 recycle() 方法在大多数情况下不起作用,并且在 58Mb 内存中工作的应用程序(有时会超过抛出一个OutOfMemoryException) 现在以指数方式消耗内存并不断增长(现在我所做的测试是分配了 231Mb 的内存),预期的行为是内存管理继续工作并且应用程序不会使用超过 60Mb.

我怎样才能避免这种情况?或者有效地回收位图?

实际上,当在设备上分配超过 390Mb 的内存时,我让它给出了 OutOfMemoryError.读取 GC_* 日志显示,有时只有 GC_FOR_ALLOC 释放了 3.8Mb,但几乎没有其他 GC 运行释放一些东西.

解决方案

你可能应该看看 有效地显示位图,其中包括几种有效处理大型位图的方法,

  • 高效加载大型位图

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) {如果(图像宽度>图像高度){inSampleSize = Math.round((float)imageHeight/(float)reqHeight);} 别的 {inSampleSize = Math.round((float)imageWidth/(float)reqWidth);}}

int inSampleSize = Math.min(imageWidth/reqWidth,imageHeight/reqHeight);

您可以设置inSampleSize,

 options.inSampleSize = inSampleSize;

然后最后确保你打电话,

options.inJustDecodeBounds = false;

否则它将返回位图为 null

  • 在 UI 线程之外处理位图

    在 UI 线程上处理位图从来都不是安全的,因此最好在后台线程中执行此操作并在处理完成后更新 UI.

  • 缓存位图

    LruCache 可从 API 12 获得,但如果您有兴趣它使用以下版本,它也可以在 支持库 也是.因此,应该使用它有效地缓存图像.您也可以将 DiskLruCache 用于您希望在外部存储中保留更长时间的图像.p>

  • 清除缓存

    有时当您的图像尺寸太大甚至缓存图像会导致 OutOfMemoryError 所以在这种情况下,当您的图像超出范围或长时间不使用时最好清除缓存,以便可以缓存其他图像.

    我为此创建了一个演示示例,您可以从这里

    下载

Before enabling largeHeap option, I was handling large bitmaps and it's consume almost the entire memory available for the application, and recycling it over navigation and loading new ones works round on almost the full heap available. However when some operations needs a bit more memory the application crashes. So I enabled largeHeap=true to have a bit more memory.

But doing this has a unexpected behavior, it's looks like that recycle() method of bitmaps do not work most of times, and the application that worked in 58Mb of memory (and exceeds sometimes throwing a OutOfMemoryException) now consumes memory exponentially and keeps growing (for now the test I did came to 231Mb allocated memory), the expected behavior is that the memory management keeps working and the application will not use more than 60Mb.

How can I avoid that? Or efficiently recycle bitmaps?

EDIT: Actually, I made it give a OutOfMemoryError when allocating more than 390Mb of memory on the device.Reading GC_* logs shown that only GC_FOR_ALLOC that freed 3.8Mb sometimes, but almost never other GC runs freed something.

解决方案

You should probably have a look at Displaying Bitmaps Efficiently which includes several ways to handle large Bitmaps Efficiently,

  • Loading Large Bitmaps Efficiently

This will give you the size of the image before downloading and on that basis you can check the size of your device and scale it using calculateInSampleSize() and decodeSampledBitmapFromResource() given in the explanation of docs.

Calculating how much we need to scale the image,

The you can set the inSampleSize,

 options.inSampleSize = inSampleSize;

Then finally make sure you call,

options.inJustDecodeBounds = false;

else it will return Bitmap as null

  • Processing Bitmaps Off the UI Thread

    Processing Bitmap on UI thread is never safe so its always better to do that in a background thread and update UI after the process is completed.

  • Caching Bitmaps

    LruCache is available from API 12 but if you are interested it using below versions it is also available in Support Library too. So caching of Images should be done efficiently using that. Also you can use DiskLruCache for images where you want then to remain for longer period in extenal storage.

  • Clearing the Cache

    Sometimes when your image size is too large even caching the image causes OutOfMemoryError so in that case its better to clear the cache when your image is out of the scope or not used for longer period so that other images can be cached.

    I had created a demo example for the same, you can download from here

这篇关于启用 largeHeap 的位图回收的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-27 13:24