|
@@ -2,8 +2,12 @@ package com.jme3.util;
|
|
|
|
|
|
import org.lwjgl.system.MemoryUtil;
|
|
import org.lwjgl.system.MemoryUtil;
|
|
|
|
|
|
|
|
+import java.lang.ref.PhantomReference;
|
|
|
|
+import java.lang.ref.ReferenceQueue;
|
|
import java.nio.Buffer;
|
|
import java.nio.Buffer;
|
|
import java.nio.ByteBuffer;
|
|
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.
|
|
* 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 {
|
|
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 volatile 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
|
|
@Override
|
|
public void destroyDirectBuffer(final Buffer buffer) {
|
|
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);
|
|
MemoryUtil.memFree(buffer);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public ByteBuffer allocate(final int size) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|