I'm developing an application that need to load Bitmap. And using a SoftReference
for the cache. I relate every soft reference with a ReferenceQueue
and using a hash map to access the SoftReference
. As following shows:
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;
}
}
Then, when I write the clean()
like :
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", "="));
}
Which check all the SoftReferences in the hash table for not null. The memcache appears good, but if I only wrote:
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", "="));
}
Which only remove the element been put into ReferenceQueue
The Log then will print more and more =
, even there is some decrease, the tendency is increase
As what is mentioned in http://www.ibm.com/developerworks/library/j-refs/
The referent
of the SoftReference
is set to null. But most of the SoftReference
was not in ReferenceQueue
. Just between the state that the object is marked as finalizable but not be finalized?
Will the Bitmap marked as finalizable but not be finalized been recycled?
I have experimented a similar issue. After sometime I had realized that is because of the way android manage bitmap. If I have not misunderstood they use "skia", a native implementation, for bitmap. So bitmaps are not allocated in the java heap but in the native heap and the java bitmap object itself is really small and a poor candidate for GC. So they provided the recycle method that free the native memory retained by a bitmap.
Sorry for my poor english.