1

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 のソフト参照が期待どおりに動作しないのはなぜですか?

4

1 に答える 1

6

私の知る限り、Java ヒープが限界まで大きくなり、新しいメモリ割り当て用のスペースがない場合にのみ、GC によってソフト参照が収集されます。

これは正しくありません。

Oracleのドキュメントによると、GC がそうするように決定した場合、指定された SoftReference はいつでも収集される可能性があります。と呼ばれる VM パラメータもあります-XX:SoftRefLRUPolicyMSPerMB。そのため、 SoftReferences は、デスクトップ JVM でもヒープ サイズを増やす前にクリアすることを意図しています (この問題の詳細については、この質問も参照してください)。

Androidのドキュメントでは、VM がこれらの参照を長期間保持することを実際に主張しないことを保証する保証はさらに少なく、明確に警告しています。

WeakReference とは異なり、SoftReference は、割り当てを満たすためにランタイムがメモリを再利用する必要があるまで、クリアされず、キューに入れられません。

個人的には「次まで」と読みますGC_FOR_ALLOC

サーキット ブレーカーにするなど、SoftReferences には確かに有効な用途がいくつかあります。リンクされた記事では、キャッシングがそれらの 1 つではない理由についても説明しています。実際に重要な方法でキャッシュを管理したい場合は、メモリ制限を使用LruCacheしてからそれをクリアしてonLowMemory()ください。または、使用後にビットマップを手放し、何をキャッシュするか、いつアプリケーションとそのキャッシュを破棄するかを OS に決定させます。

于 2015-07-20T09:12:02.857 に答える