Использование SoftReference для кэширования Bitmap на Android вызывает OOM - PullRequest
2 голосов
/ 22 ноября 2011

Я разрабатываю приложение, которое должно загрузить Bitmap.И используя SoftReference для кеша.Я связываю каждую мягкую ссылку с ReferenceQueue и использую хэш-карту для доступа к SoftReference.Как показано ниже:

public static class MemCache {

    final private ReferenceQueue<Bitmap> queue = new ReferenceQueue<Bitmap>();
    private Map<String, SoftReference<Bitmap>> hash = null;

    public MemCache() {
        hash = Collections.synchronizedMap(
            new LinkedHashMap<String, SoftReference<Bitmap>>()
        );
    }

    public synchronized Bitmap put(String key, Bitmap value) {
        clean();
        SoftReference<Bitmap> ref = new SoftReference<Bitmap>(value, queue);
        SoftReference<Bitmap> res = hash.put(key, ref);
        if (res == null) return null;
        return res.get();
    }

    public synchronized Bitmap get(Object key) {
        clean();
        SoftReference<Bitmap> ref = hash.get(key);
        if (ref == null) return null;
        Bitmap val = ref.get();
        if (val != null) return val;
        hash.remove(key);
        return null;
    }
}

Затем, когда я пишу clean(), например:

    private synchronized void clean() {
        Reference<? extends Bitmap> sv;
        while ((sv = queue.poll()) != null)
            hash.remove(sv);
        Queue<String> toRemove = new LinkedList<String>();
        for(Entry<String, SoftReference<Bitmap>> e : hash.entrySet()){
            if(e.getValue()==null) continue;
            if(e.getValue().get()==null) 
                toRemove.add(e.getKey());
        }
        String s;
        while((s = toRemove.poll())!= null)
            hash.remove(s);
        Log.e("ImageCacheManager", "MemCache Size/2:" + new String(new char[hash.size() / 2]).replace("\0", "="));
    }

, которые проверяют все SoftReferences в хеш-таблице на ненулевое значение.Memcache выглядит хорошо, но если я только написал:

    private synchronized void clean() {
        Reference<? extends Bitmap> sv;
        while ((sv = queue.poll()) != null)
            hash.remove(sv);
        Log.e("ImageCacheManager", "MemCache Size/2:" + new String(new char[hash.size() / 2]).replace("\0", "="));
    }

, который удаляет только тот элемент, который был помещен в ReferenceQueue. Журнал будет печатать все больше и больше =, даже если есть некоторое уменьшение, тенденция будетувеличение

Как указано в http://www.ibm.com/developerworks/library/j-refs/

referent из SoftReference установлено в ноль.Но большая часть SoftReference не была в ReferenceQueue.Просто между состоянием, что объект помечен как финализируемый, но не финализированный?Будет ли растровое изображение, помеченное как финализируемое, но не финализированное, переработано?

1 Ответ

5 голосов
/ 22 ноября 2011

Я экспериментировал с подобной проблемой.Через некоторое время я понял, что из-за того, как Android управляет растровым изображением.Если я не понял неправильно, они используют «skia», нативную реализацию, для растрового изображения.Таким образом, растровые изображения распределяются не в куче Java, а в собственной куче, а сам объект растрового изображения Java действительно мал и является плохим кандидатом на сборщик мусора.Таким образом, они предоставили метод recycle, который освобождает собственную память, сохраняемую растровым изображением.

Извините за мой плохой английский.

...