软引用在Android上的行为不如预期

时间:2015-07-20 05:11:33

标签: android soft-references

我在Android上使用软参考时遇到了一个奇怪的问题。 我实现了一个用于位图缓存的类,源代码如下:

public class ImageCache
{
    private static HashMap<String, SoftReference<Bitmap>> mCache = new HashMap<String, SoftReference<Bitmap>>();
    private static final String TAG = "ImageCache";
    public static Bitmap getBitmap(String url)
    {
        Bitmap bitmap = null;
        if (mCache.containsKey(url))
        {
            Log.d(TAG, "use cache: " + url);
            bitmap = mCache.get(url).get();
            if (bitmap != null)
            {
                return bitmap;
            }
            else
            {
                Log.w(TAG, "#######################soft ref was collected!!!");
            }
        }
        bitmap = BitmapFactory.decodeFile(url);

        if (bitmap == null)
        {
            Log.e(TAG, "#####jpg not found");
            return null;
        }
        bitmap = Bitmap.createScaledBitmap(bitmap, 320, 240, false);
        synchronized (mCache) {
            mCache.put(url, new SoftReference<Bitmap>(bitmap));
        }
        return bitmap;
    }
}

但我通过logcat发现经常收集软引用。日志是:

#######################soft ref was collected!!!

据我所知,只有当java堆增长到极限并且没有新的内存分配空间时,GC才会收集软引用。

但为什么Android上的软参考表现不如预期?

1 个答案:

答案 0 :(得分:4)

  

据我所知,只有当java堆增长到极限并且没有新的内存分配空间时,GC才会收集软引用。

这是不正确的。

根据Oracle documentation,如果GC决定这样做,任何给定的SoftReference都可以随时收集。甚至还有VM参数,称为-XX:SoftRefLRUPolicyMSPerMB。因此,即使在桌面JVM上也必须增加堆大小,SoftReferences 意味着才能被清除(另请参阅this question了解有关此事的一些额外细节)。

Android documentation提供更少的保证,clearly warns,VM实际上不会坚持长时间保留这些引用:

  

与WeakReference不同,SoftReference不会被清除并排队,直到运行时必须回收内存以满足分配。

我个人认为“直到下一个GC_FOR_ALLOC”。

SoftReferences肯定有一些有效用途,例如将它们设为circuit breaker。链接的文章还解释了为什么缓存不是其中之一。如果您想以实际方式管理缓存,请使用内存有限LruCache并从onLowMemory()清除缓存。或者,更好的是,只需在使用它们之后释放Bitmaps并让操作系统决定,缓存什么以及何时销毁应用程序及其缓存。