package org.xith3d.utility.memory; import org.jagatoo.util.nio.BufferUtils; import org.xith3d.utility.logging.X3DLog; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * Created by smeier on 2/11/15. * A singleton that manages a growable pool of ByteBuffers for use in taking screenshots. * Using the pool should increase performance over repeated instantiation-destruction, * and prevent a memory leak related to generation of ByteBuffers in Windows. * * The public methods are considered thread-safe. */ public class ByteBufferPool { private static ByteBufferPool singleton; /** * Retrieves the singleton instance of the ByteBufferPool, and creates a new instance of one does not already exist. * @return the singleton instance of the ByteBufferPool. */ public synchronized static ByteBufferPool getSingleton() { if (singleton == null) { singleton = new ByteBufferPool(); } return singleton; } private List<ByteBuffer> availableDroplets; private int leasedDroplets; public ByteBufferPool() { availableDroplets = new ArrayList<ByteBuffer>(); leasedDroplets = 0; } /** * Leases a ByteBuffer from the pool. A new ByteBuffer instance will be created if one that matches your parameters is not available. * This method is considered thread-safe. * @param capacity the capacity of the requested ByteBuffer, in bytes. * @return a ByteBuffer with the requested capacity. The buffer may contain preexisting data. */ public synchronized ByteBuffer getDroplet(int capacity) { ByteBuffer droplet = null; // Try to find an existing, free droplet with the requested capacity before creating a new one for (int i=0; (i < availableDroplets.size()) && (droplet == null); i++) { if (availableDroplets.get(i).capacity() == capacity) { droplet = availableDroplets.remove(i); } } if (droplet == null) { droplet = BufferUtils.createByteBuffer(capacity); X3DLog.debug("ByteBufferPool created droplet #" + (size() + 1) + " with a capacity of " + capacity + " bytes."); if (size() > 9) { X3DLog.error("ByteBufferPool has created and leased more than 10 droplets. This is likely an indication of a memory leak."); } } leasedDroplets++; return droplet; } /** * Returns a ByteBuffer to the pool. Do not keep the reference to the object, as another method or thread may use it. * @param droplet the ByteBuffer to return to the pool. */ public synchronized void releaseDroplet(ByteBuffer droplet) { availableDroplets.add(droplet); leasedDroplets--; } /** * @return the total number of droplets owned by the pool, including both available and leased. */ public synchronized int size() { return availableDroplets.size() + leasedDroplets; } }