FileDocCategorySizeDatePackage
UnrefedPooledCache.javaAPI DocAndroid 5.1 API8108Thu Mar 12 22:22:50 GMT 2015com.android.bitmap

UnrefedPooledCache

public class UnrefedPooledCache extends Object implements PooledCache
An alternative implementation of a pool+cache. This implementation only counts unreferenced objects in its size calculation. Internally, it never evicts from its cache, and instead {@link #poll()} is allowed to return unreferenced cache entries.

You would only use this kind of cache if your objects are interchangeable and have significant allocation cost, and if your memory footprint is somewhat flexible.

Because this class only counts unreferenced objects toward targetSize, it will have a total memory footprint of: (targetSize) + (# of threads concurrently writing to cache) + (total size of still-referenced entries)

Fields Summary
private final LinkedHashMap
mCache
private final LinkedBlockingQueue
mPool
private final int
mTargetSize
private final android.util.LruCache
mNonPooledCache
private static final boolean
DEBUG
private static final String
TAG
Constructors Summary
public UnrefedPooledCache(int targetSize, float nonPooledFraction)

param
targetSize not exactly a max size in practice
param
nonPooledFraction the fractional portion in the range [0.0,1.0] of targetSize to dedicate to non-poolable entries


                                  
         
        mCache = new LinkedHashMap<K, V>(0, 0.75f, true);
        mPool = new LinkedBlockingQueue<V>();
        final int nonPooledSize = Math.round(targetSize * nonPooledFraction);
        if (nonPooledSize > 0) {
            mNonPooledCache = new NonPooledCache(nonPooledSize);
        } else {
            mNonPooledCache = null;
        }
        mTargetSize = targetSize - nonPooledSize;
    
Methods Summary
public voidclear()

        mCache.clear();
        mPool.clear();
    
public Vget(K key, boolean incrementRefCount)

        Trace.beginSection("cache get");
        synchronized (mCache) {
            V result = mCache.get(key);
            if (result == null && mNonPooledCache != null) {
                result = mNonPooledCache.get(key);
            }
            if (incrementRefCount && result != null) {
                result.acquireReference();
            }
            Trace.endSection();
            return result;
        }
    
public voidoffer(V value)

        Trace.beginSection("pool offer");
        if (value.getRefCount() != 0 || !value.isEligibleForPooling()) {
            Trace.endSection();
            throw new IllegalArgumentException("unexpected offer of an invalid object: " + value);
        }
        mPool.offer(value);
        Trace.endSection();
    
public Vpoll()

        Trace.beginSection("pool poll");
        final V pooled = mPool.poll();
        if (pooled != null) {
            Trace.endSection();
            return pooled;
        }

        synchronized (mCache) {
            int unrefSize = 0;
            Map.Entry<K, V> eldestUnref = null;
            for (Map.Entry<K, V> entry : mCache.entrySet()) {
                final V value = entry.getValue();
                if (value.getRefCount() > 0 || !value.isEligibleForPooling()) {
                    continue;
                }
                if (eldestUnref == null) {
                    eldestUnref = entry;
                }
                unrefSize += sizeOf(value);
                if (unrefSize > mTargetSize) {
                    break;
                }
            }
            // only return a scavenged cache entry if the cache has enough
            // eligible (unreferenced) items
            if (unrefSize <= mTargetSize) {
                if (DEBUG) {
                    Log.e(TAG, "POOL SCAVENGE FAILED, cache not fully warm yet. szDelta="
                            + (mTargetSize-unrefSize));
                }
                Trace.endSection();
                return null;
            } else {
                mCache.remove(eldestUnref.getKey());
                if (DEBUG) {
                    Log.e(TAG, "POOL SCAVENGE SUCCESS, oldKey=" + eldestUnref.getKey());
                }
                Trace.endSection();
                return eldestUnref.getValue();
            }
        }
    
public Vput(K key, V value)

        Trace.beginSection("cache put");
        // Null values not supported.
        if (value == null) {
            Trace.endSection();
            return null;
        }
        synchronized (mCache) {
            final V prev;
            if (value.isEligibleForPooling()) {
                prev = mCache.put(key, value);
            } else if (mNonPooledCache != null) {
                prev = mNonPooledCache.put(key, value);
            } else {
                prev = null;
            }
            Trace.endSection();
            return prev;
        }
    
protected intsizeOf(V value)

        return 1;
    
public java.lang.StringtoDebugString()

        if (DEBUG) {
            final StringBuilder sb = new StringBuilder("[");
            sb.append(super.toString());
            int size = 0;
            synchronized (mCache) {
                sb.append(" poolCount=");
                sb.append(mPool.size());
                sb.append(" cacheSize=");
                sb.append(mCache.size());
                if (mNonPooledCache != null) {
                    sb.append(" nonPooledCacheSize=");
                    sb.append(mNonPooledCache.size());
                }
                sb.append("\n---------------------");
                for (V val : mPool) {
                    size += sizeOf(val);
                    sb.append("\n\tpool item: ");
                    sb.append(val);
                }
                sb.append("\n---------------------");
                for (Map.Entry<K, V> item : mCache.entrySet()) {
                    final V val = item.getValue();
                    sb.append("\n\tcache key=");
                    sb.append(item.getKey());
                    sb.append(" val=");
                    sb.append(val);
                    size += sizeOf(val);
                }
                sb.append("\n---------------------");
                if (mNonPooledCache != null) {
                    for (Map.Entry<K, V> item : mNonPooledCache.snapshot().entrySet()) {
                        final V val = item.getValue();
                        sb.append("\n\tnon-pooled cache key=");
                        sb.append(item.getKey());
                        sb.append(" val=");
                        sb.append(val);
                        size += sizeOf(val);
                    }
                    sb.append("\n---------------------");
                }
                sb.append("\nTOTAL SIZE=" + size);
            }
            sb.append("]");
            return sb.toString();
        } else {
            return null;
        }