-->

与largeHeap位图的循环启用(Bitmap recycle with largeHeap en

2019-06-18 10:28发布

使前largeHeap选项,我正在处理大的位图,它的消耗几乎可用于应用程序的整个内存,回收过来的导航和加载新的一轮工作几乎全部可用堆。 然而,当某些操作需要更多的内存的应用程序崩溃。 所以我启用largeHeap=true能有更多一点的内存。

但这样做有一个意外的行为,它看起来像recycle()位图的方法不工作的大部分时间,而在内存58MB工作的应用程序(和超过有时抛出OutOfMemoryException )现在消耗内存成倍而且还在不断增加(对于现在的测试我也来到了231Mb分配的内存),预期的行为是内存管理一直工作,应用程序将不会使用超过60MB以上。

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

编辑:其实,我把它给一个OutOfMemoryError比的设备上存储390MB分配更多的时候。 阅读GC_ *显示日志,只有那些释放3.8MB的时候,但是几乎从来没有其他GC运行中解脱出来的东西GC_FOR_ALLOC。

Answer 1:

你或许应该看看显示位图高效 ,其中包括几种方式来有效地处理大量位图,

  • 加载大型高效位图
 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;

否则,它将返回位图作为null

  • 处理位图关闭UI线程

    在UI线程处理位图是永远安全的所以它总是更好地完成处理后做,在后台线程和更新UI。

  • 位图缓存

    LruCache可从API 12,但如果你有兴趣使用它下面的版本中,它也可用于支持库了。 所以无论图像的缓存应该有效利用来完成。 你也可以使用DiskLruCache为您希望再留在extenal储存较长时间的图像。

  • 清除缓存

    有时候,当你的图片尺寸过大,甚至缓存图像导致OutOfMemoryError所以在这种情况下,它能够更好地清除缓存,当您的图像超出范围或不使用较长的时间,以便其他图像可以被缓存。

    我创造了一个相同的演示的例子,你可以下载在这里



Answer 2:

你的情况下,行为与预期相同。 蜂窝之前, recycle()被无条件释放内存。 但在3.0及以上,位图是正常垃圾回收存储器的一部分。 你必须在设备上大量的RAM,你允许JVM比58M限制分配更多,现在的垃圾收集器是满意,就没有动力收回你的位图占用的内存。

您可以通过使用RAM的控制量在模拟器上运行验证这一点,或加载某些存储设备上消费服务 - GC将跳转到工作。 你可以使用DDMS进一步调查您的内存使用情况。

您可以尝试为位图内存管理的一些解决方案: 位图在Android的 位图的内存泄漏 http://blog.javia.org/how-to-work-around-androids-24-mb-memory-limit/ ,但随着开始正式Android的位图的提示 ,作为解释@Lalit Poptani的详细的解答 。

需要注意的是移动的位图到OpenGL的内存作为纹理有一些性能问题(但完美的,如果你将渲染通过OpenGL的到底这些位图)。 这两种纹理和malloc的解决方案需要您明确释放你不再使用位图的内存。



Answer 3:

当然@Lalit Poptani答案是做到这一点,你真的应该扩展您的Bitmaps ,如果他们是非常大的。 优选的方式是,这样做是server-side ,如果这是可能的,因为你也会减少NetworkOperation时间。

关于执行MemoryCacheDiskCache这又是做到这一点的最好办法,但我还是建议使用现有的库,这正是这么做的( Ignition ),您将节省大量的时间,而且也有很多内存泄漏,因为因为你Heap没有得到后清空GC我可以假设你可能有一些memory leaks了。



Answer 4:

为了解决你的困境,我相信这是预期的行为。

如果你想释放内存,你可以偶尔调用System.gc() ,但实际上,你应该在大多数情况下让它管理垃圾收集本身。

我的建议是,你保持某种其通过计算每个位被占用的字节数跟踪它自己的内存使用的一个简单的缓存(URL /文件名,位图)。

/**
 * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config
 * @param width
 * @param height
 * @param config
 * @return
 */
public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){
    long pixels=width*height;
    switch(config){
    case ALPHA_8: // 1 byte per pixel
        return pixels;
    case ARGB_4444: // 2 bytes per pixel, but depreciated
        return pixels*2;
    case ARGB_8888: // 4 bytes per pixel
        return pixels*4;
    case RGB_565: // 2 bytes per pixel
        return pixels*2;
    default:
        return pixels;
    }
}

然后您查询应用程序是使用多少内存,多少是可用的,可能采取一半,并尽量保持下,总的图像缓存大小,通过简单地移除(非关联)从列表旧图像时,您都上来了针对此限制, 不可回收利用 。 让垃圾收集清理位图时,他们都从缓存中derefrrenced,并且不被任何意见。

/**
 * Calculates and adjusts the cache size based on amount of memory available and average file size
 * @return
 */
synchronized private int calculateCacheSize(){
    if(this.cachedBitmaps.size()>0){
        long maxMemory = this.getMaxMemory(); // Total max VM memory minus runtime memory 
        long maxAllocation = (long) (ImageCache.MEMORY_FRACTION*maxMemory);
        long avgSize = this.bitmapCacheAllocated / this.cachedBitmaps.size();
        this.bitmapCacheSize = (int) (maxAllocation/avgSize);
    }
    return this.bitmapCacheSize;
}

我会建议你使用远离recycle()它会导致很多断断续续的例外(比如当看似敲定观点尝试访问再生位图),并在一般看来马车。



Answer 5:

你必须非常小心的跟在Android上处理位图。 让我换一种说法:你要注意,即使与4个音乐会的RAM系统处理位图。 如何大是这些家伙,你有很多吗? 您可能必须砍和瓷砖它,如果它是大的。 请记住,您使用使用视频RAM,这是一个不同的动物比系统内存。

预蜂窝,所述位图被分配在C ++层上,使RAM的使用是不可见的Java和不能被垃圾收集器来访问。 与RGB24颜色空间A 3 MP未压缩位图使用了大约9-10兆字节(约2048x1512)。 因此,较大的图像可以很容易地填补你的堆。 还记得,在无论是用于视频RAM(有时专用RAM,有时用系统共享),数据通常存储未压缩。

基本上,如果你的目标前蜂窝设备,你几乎要管理的位图对象,如果你是一个编码C ++程序。 运行位再循环()onDestory()通常工作,如果没有很多的图像,但如果你有一吨在屏幕上的图像,你可能需要处理他们即时。 此外,如果您启动其他活动,你可能要考虑将在逻辑引入的onPause()和的onResume()。

您也可以使用Android文件系统或SQLite的缓存图片时,他们没有在视频RAM。 您可以与如果你使用的是像.JPG格式或巴纽有很多重复的数据在RAM中缓存它脱身/



文章来源: Bitmap recycle with largeHeap enabled