Explorar el Código

Implemented auto free LWJGL byte buffers.

javasabr hace 8 años
padre
commit
2136dc4484

+ 83 - 1
jme3-lwjgl3/src/main/java/com/jme3/util/LWJGLBufferAllocator.java

@@ -2,8 +2,12 @@ package com.jme3.util;
 
 import org.lwjgl.system.MemoryUtil;
 
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * The implementation of the {@link BufferAllocator} which use {@link MemoryUtil} to manage memory.
@@ -12,13 +16,91 @@ import java.nio.ByteBuffer;
  */
 public class LWJGLBufferAllocator implements BufferAllocator {
 
+    /**
+     * The reference queue.
+     */
+    private static final ReferenceQueue<Buffer> DUMMY_QUEUE = new ReferenceQueue<Buffer>();
+
+    /**
+     * The LWJGL byte buffer deallocator.
+     */
+    private static class Deallocator extends PhantomReference<ByteBuffer> {
+
+        /**
+         * The address of LWJGL byte buffer.
+         */
+        private Long address;
+
+        public Deallocator(final ByteBuffer referent, final ReferenceQueue<? super ByteBuffer> queue,
+                           final Long address) {
+            super(referent, queue);
+            this.address = address;
+        }
+
+        /**
+         * @param address the address of LWJGL byte buffer.
+         */
+        void setAddress(final Long address) {
+            this.address = address;
+        }
+
+        /**
+         * Free memory.
+         */
+        void free() {
+            if (address == null) return;
+            MemoryUtil.nmemFree(address);
+            DEALLOCATORS.remove(address);
+        }
+    }
+
+    /**
+     * The cleaner thread.
+     */
+    private static final Thread CLEAN_THREAD = new Thread(LWJGLBufferAllocator::freeByteBuffers);
+
+    /**
+     * The map with created deallocators.
+     */
+    private static final Map<Long, Deallocator> DEALLOCATORS = new ConcurrentHashMap<>();
+
+    static {
+        CLEAN_THREAD.setDaemon(true);
+        CLEAN_THREAD.setName("Thread to free LWJGL byte buffers");
+        CLEAN_THREAD.start();
+    }
+
+    /**
+     * Free unnecessary LWJGL byte buffers.
+     */
+    private static void freeByteBuffers() {
+        try {
+            for (;;) {
+                final Deallocator deallocator = (Deallocator) DUMMY_QUEUE.remove();
+                deallocator.free();
+            }
+        } catch (final InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
     @Override
     public void destroyDirectBuffer(final Buffer buffer) {
+
+        final long address = MemoryUtil.memAddress((ByteBuffer) buffer);
+
+        // disable deallocator
+        final Deallocator deallocator = DEALLOCATORS.remove(address);
+        if (deallocator != null) deallocator.setAddress(null);
+
         MemoryUtil.memFree(buffer);
     }
 
     @Override
     public ByteBuffer allocate(final int size) {
-        return MemoryUtil.memAlloc(size);
+        final Long address = MemoryUtil.nmemAlloc(size);
+        final ByteBuffer byteBuffer = MemoryUtil.memByteBuffer(address, size);
+        DEALLOCATORS.put(address, new Deallocator(byteBuffer, DUMMY_QUEUE, address));
+        return byteBuffer;
     }
 }