/** * */ package com.browseengine.bobo.util; import java.lang.ref.WeakReference; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.apache.log4j.Logger; public class MemoryManager<T> implements MemoryManagerAdminMBean { private static final Logger log = Logger.getLogger(MemoryManager.class.getName()); private static final int[] sizetable; private final AtomicLong _hits = new AtomicLong(0); private final AtomicLong _miss = new AtomicLong(0); static { int initsize = 1024; double ratio = 1.3; int l = (int) (Math.log(Integer.MAX_VALUE / initsize) / Math.log(ratio)) + 1; sizetable = new int[l]; sizetable[0] = initsize; for (int i = 1; i < sizetable.length; i++) { sizetable[i] = (int) (sizetable[i - 1] * ratio); } } private final ConcurrentHashMap<Integer, ConcurrentLinkedQueue<WeakReference<T>>> _sizeMap = new ConcurrentHashMap<Integer, ConcurrentLinkedQueue<WeakReference<T>>>(); private volatile ConcurrentLinkedQueue<T> _releaseQueue = new ConcurrentLinkedQueue<T>(); private volatile ConcurrentLinkedQueue<T> _releaseQueueb = new ConcurrentLinkedQueue<T>(); private final AtomicInteger _releaseQueueSize = new AtomicInteger(0); private final Initializer<T> _initializer; private final Thread _cleanThread; public MemoryManager(Initializer<T> initializer) { this._initializer = initializer; _cleanThread = new Thread(new Runnable() { @Override public void run() { T buf = null; while (true) { synchronized (MemoryManager.this) { try { MemoryManager.this.wait(10); } catch (InterruptedException e) { log.error(e); } } ConcurrentLinkedQueue<T> t = _releaseQueue; _releaseQueue = _releaseQueueb; _releaseQueueb = t; while ((buf = _releaseQueueb.poll()) != null) { ConcurrentLinkedQueue<WeakReference<T>> queue = _sizeMap.get(_initializer.size(buf)); // buf is wrapped in WeakReference. this allows GC to reclaim the buffer memory _initializer.init(buf);// pre-initializing the buffer in parallel so we save time when // it is requested later. queue.offer(new WeakReference<T>(buf)); _releaseQueueSize.decrementAndGet(); } buf = null; } } }); _cleanThread.setDaemon(true); _cleanThread.start(); } public MemoryManagerAdminMBean getAdminMBean() { return this; } @Override public long getNumCacheMisses() { return _miss.get(); } @Override public long getNumCacheHits() { return _hits.get(); } @Override public double getHitRate() { long miss = _miss.get(); long hit = _hits.get(); return (double) hit / (double) (hit + miss); } /** * @return an initialized instance of type T. The size of the instance may not be the same as the requested size. */ public T get(int reqsize) { return _initializer.newInstance(reqsize); // long t0 = System.currentTimeMillis(); // int size = reqsize; // for(int i = 0; i<sizetable.length; i++) // { // if (sizetable[i] >= reqsize) // { // size = sizetable[i]; // break; // } // } // ConcurrentLinkedQueue<WeakReference<T>> queue = _sizeMap.get(size); // if (queue==null) // { // queue = new ConcurrentLinkedQueue<WeakReference<T>>(); // _sizeMap.putIfAbsent(size, queue); // queue = _sizeMap.get(size); // } // while(true) // { // WeakReference<T> ref = (WeakReference<T>) queue.poll(); // if(ref != null) // { // T buf = ref.get(); // if(buf != null) // { // _hits.incrementAndGet(); // return buf; // } // } // else // { // T ret = _initializer.newInstance(size); // _miss.incrementAndGet(); // long hit = _hits.get(); // if (hit > Long.MAX_VALUE/2) // { // _hits.set(0); // _miss.set(0); // } // return ret; // } // } } /** * return the instance to the manager after use * @param buf */ public void release(T buf) { // if (_releaseQueueSize.get()>8000) // { // log.info("release queue full"); // synchronized(MemoryManager.this) // { // MemoryManager.this.notifyAll(); // } // return; // } // if(buf != null) // { // _releaseQueue.offer(buf); // _releaseQueueSize.incrementAndGet(); // synchronized(MemoryManager.this) // { // MemoryManager.this.notifyAll(); // } // } } public static interface Initializer<E> { public E newInstance(int size); public int size(E buf); public void init(E buf); } }