我应该在什么时候回收位图使用LRUCache? [英] When should I recycle a bitmap using LRUCache?

查看:223
本文介绍了我应该在什么时候回收位图使用LRUCache?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 LRUCache 到存储在文件系统上的缓存位图。我建的高速缓存基于这里的例子:<一href="http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html">http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

问题是,我看到内存溢出崩溃时频繁使用的应用程序。我相信,当LRUCache驱逐的图像以腾出空间给一个又一个,内存不被释放。

我添加了一个调用Bitmap.recycle()当图像被逐出:

  //使用可用内存的1/8这个内存缓存
    最终诠释CACHESIZE = 1024 * 1024 * memClass / 8;
                mImageCache =新LruCache&LT;字符串,位图&GT;(CACHESIZE){
                @覆盖
                保护INT整型尺寸(字符串键,位图位图){
                    返回bitmap.getByteCount();
                }

                @覆盖
                保护无效entryRemoved(布尔拆迁户,串键,位图oldBitmap,位图newBitmap){
                    oldBitmap.recycle();
                    oldBitmap = NULL;
                }
            };
 

这修复了崩溃,但它也导致了图像的有时的没有出现在应用程序(只是一个黑色的空间,图像应该是)。发生我看到这则消息在我logcat中的任何时间:无法生成的纹理从位图

一个快速谷歌搜索发现,这种情况正在发生,因为这是显示图像已被回收。

那么这里发生了什么?为什么被回收的图像仍处于LRUCache如果我只是回收他们,他们已经被删除后? 什么是替代实施缓存? Android的文档明确规定的任何LRUCache是​​要走的路,但他们没有提到需要回收位图或如何做到这一点。

解决: 如果它有用的人一样,所建议的接受的答案,要解决这个问题的方法是的不是的做什么,我在上面的code例子一样(不回收的位图 entryRemoved()电话)。

相反,当你与一个ImageView的完成后(如的onPause()的活动时,或者当视图的回收再利用转接器)检查的位图仍然在高速缓存中(我加了 isImageInCache()的方法来我的缓存类),如果不是的话,那么回收的位图。否则,不要管它。这个固定我的内存不足其中仍在使用的例外和prevented回收位图。

解决方案
  

我相信,当LRUCache驱逐的图像以腾出空间给一个又一个,内存不被释放。

这不会是,直到位图被回收或垃圾收集。

  

一个快速谷歌搜索发现,这种情况正在发生,因为这是显示图像已被回收。

这就是为什么你不应该回收存在。

  

为什么被回收的图像仍处于LRUCache如果我只是回收他们,他们已经被删除后?

presumably,他们不是在 LRUCache 。他们是在的ImageView 或别的,依然采用了位图

  

什么是替代实施缓存?

有关参数的缘故,让我们假设你正在使用的ImageView的位图对象窗口小部件,如行的的ListView

当你与做了位图(例如,行中的的ListView 循环),你检查看它是否仍然在缓存中。如果是,你不要管它。如果不是,你循环()吧。

缓存只是让你知道哪些位图对象是值得持有到。缓存没有办法,如果位图仍在使用的地方知道的。

顺便说一句,如果你是在API级别11+,可以考虑使用<一个href="http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inBitmap"><$c$c>inBitmap. OutOMemoryErrors 被触发时,分配无法实现。上次我检查,Android不具备压缩垃圾收集器,这样你就可以得到一个的OutOfMemoryError 因碎片(要分配更大的东西相比,最大的单一可用块)。

I'm using an LRUCache to cache bitmaps which are stored on the file system. I built the cache based on the examples here: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

The problem is that I'm seeing OutOfMemory crashes frequently while using the app. I believe that when the LRUCache evicts an image to make room for another one, the memory is not being freed.

I added a call to Bitmap.recycle() when an image is evicted:

  // use 1/8 of the available memory for this memory cache
    final int cacheSize = 1024 * 1024 * memClass / 8;
                mImageCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    return bitmap.getByteCount();
                }

                @Override
                protected void entryRemoved(boolean evicted, String key, Bitmap oldBitmap, Bitmap newBitmap) {
                    oldBitmap.recycle();
                    oldBitmap = null;
                }
            };

This fixes the crashes, however it also results in images sometimes not appearing in the app (just a black space where the image should be). Any time that occurs I see this message in my Logcat: Cannot generate texture from bitmap.

A quick google search reveals that this is happening because the image which is displaying has been recycled.

So what is happening here? Why are recycled images still in the LRUCache if I'm only recycling them after they've been removed? What is the alternative for implementing a cache? The Android docs clearly state that LRUCache is the way to go, but they do not mention the need to recycle bitmaps or how to do so.

RESOLVED: In case its useful to anyone else, the solution to this problem as suggested by the accepted answer is to NOT do what I did in the code example above (don't recycle the bitmaps in the entryRemoved() call).

Instead, when you're finished with an ImageView (such as onPause() in an activity, or when a view is recycled in an adapter) check if the bitmap is still in the cache (I added a isImageInCache() method to my cache class) and, if it's not, then recycle the bitmap. Otherwise, leave it alone. This fixed my OutOfMemory exceptions and prevented recycling bitmaps which were still being used.

解决方案

I believe that when the LRUCache evicts an image to make room for another one, the memory is not being freed.

It won't be, until the Bitmap is recycled or garbage-collected.

A quick google search reveals that this is happening because the image which is displaying has been recycled.

Which is why you should not be recycling there.

Why are recycled images still in the LRUCache if I'm only recycling them after they've been removed?

Presumably, they are not in the LRUCache. They are in an ImageView or something else that is still using the Bitmap.

What is the alternative for implementing a cache?

For the sake of argument, let's assume you are using the Bitmap objects in ImageView widgets, such as in rows of a ListView.

When you are done with a Bitmap (e.g., row in a ListView is recycled), you check to see if it is still in the cache. If it is, you leave it alone. If it is not, you recycle() it.

The cache is simply letting you know which Bitmap objects are worth holding onto. The cache has no way of knowing if the Bitmap is still being used somewhere.

BTW, if you are on API Level 11+, consider using inBitmap. OutOMemoryErrors are triggered when an allocation cannot be fulfilled. Last I checked, Android does not have a compacting garbage collector, so you can get an OutOfMemoryError due to fragmentation (want to allocate something bigger than the biggest single available block).

这篇关于我应该在什么时候回收位图使用LRUCache?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆