Soft reference does not behave as expected on Android

浪尽此生 提交于 2019-12-13 01:28:02

问题


I encountered a strange problem when I was using soft reference on Android. I implemented a class for bitmap cache, the source code is as follows:

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;
    }
}

But I found through the logcat that soft reference is collected frequently. The log is:

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

As far as I know, soft reference will be collected by GC only if java heap grow to its limit and there is no space for a new memory allocation.

But why soft reference on Android does not behave as expected?


回答1:


As far as I know, soft reference will be collected by GC only if java heap grow to its limit and there is no space for a new memory allocation.

This is incorrect.

According to Oracle documentation, any given SoftReference may be collected anytime, if the GC makes decision to do so. There is even VM parameter, called -XX:SoftRefLRUPolicyMSPerMB. So SoftReferences are meant to get cleared before having to increase heap size even on desktop JVMs (see also this question for some extra details on the matter).

Android documentation gives even less guarantees, and clearly warns, that the VM won't actually insist on keeping those references around for long:

Unlike a WeakReference, a SoftReference will not be cleared and enqueued until the runtime must reclaim memory to satisfy an allocation.

Which I personally read as "until next GC_FOR_ALLOC".

There are certainly some valid uses for SoftReferences, such as making them a circuit breaker. The linked article also explains, why caching is not one of them. If you want to manage your cache in manner, that actually matters, use memory-limited LruCache and clear that from onLowMemory(). Or, better yet, just let go of Bitmaps after using them and let the OS decide, what to cache and when to destroy your application and it's caches.



来源:https://stackoverflow.com/questions/31509201/soft-reference-does-not-behave-as-expected-on-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!