Ответ 1
Прямые буферы NIO используют неуправляемую память. Это означает, что они расположены в собственной куче, а не в куче Java. Как следствие, они освобождаются только тогда, когда JVM не хватает памяти в куче Java, а не в собственной куче. Другими словами, это неуправляемо = вам решать управлять ими. Принудительный сбор мусора не рекомендуется и большую часть времени не решает эту проблему.
Когда вы знаете, что прямой буфер NIO стал для вас бесполезным, вы должны освободить его собственную память, используя его sun.misc.Cleaner(StaxMan прав) и вызвать clean() (кроме Apache Harmony), вызвать free() (с Apache Harmony) или используйте лучший публичный API для этого (возможно, в Java> 12, AutoCleaning, расширяющий AutoCloseable?).
Это не работа JOGL, вы можете использовать простой Java-код, чтобы сделать это самостоятельно. Мой пример находится под лицензией GPL v2, а этот пример - под более разрешительной лицензией.
Edit.: Мой последний пример работает даже с Java 1.9 и поддерживает OpenJDK, Oracle Java, Sun Java, Apache Harmony, GNU Classpath и Android. Возможно, вам придется удалить синтаксический сахар, чтобы он работал с Java & lt; 1,7 (несколько уловов, алмазы и дженерики).
Ссылка: http://www.ibm.com/developerworks/library/j-nativememory-linux/
Direct ByteBuffer объекты автоматически очищают свои собственные буферы но может сделать это только как часть кучи Java GC - так они не делают автоматически реагировать на давление на родную кучу. GC происходит только когда куча Java становится настолько полной, она не может обслуживать выделение кучи запрос или если приложение Java явно запрашивает его (не рекомендуется, потому что это вызывает проблемы с производительностью).
Ссылка: http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#direct
Содержимое прямых буферов может находиться за пределами обычной кучи, собираемой мусором.
Это решение (в этом JEP, все еще черновик, вероятно, недоступно в Java 1.9) очень многообещающе, нам не нужно будет использовать непубличные API.
public long memory(long index) {
// The scope where the memory region is available
// Implements AutoClosable but 'close' can be called manually as well
try (Scope scope = new NativeScope()) {
// Allocate the actual memory area, in this case in the style of a "long-array"
Pointer<Long> ptr = scope.allocate(
NativeLibrary.createLayout(long.class), numElements);
// Get the reference to a certain element
Reference<Long> ref = ptr.offset(index).deref();
// Set a value to this element through the reference
ref.set(Long.MAX_VALUE);
// Read the value of an element
return ref.get();
}
}
Примечание: sun.misc.Cleaner был перемещен в jdk.internal.ref.Cleaner в Java 1.9 в модуле "java.base", последний реализовал Java. lang.Runnable (спасибо Алану Бейтману за напоминание об этой разнице) в течение короткого времени, но это больше не так. Вы должны вызвать sun.misc.Unsafe.invokeCleaner(), это сделано в JogAmp Gluegen. Я предпочел использовать Cleaner в качестве Runnable, поскольку он избегал полагаться на sun.misc.Unsafe, но теперь он не работает.
Мое последнее предложение работает с Java 9, 10, 11 и 12.
Существует хороший пример в Lucene под более разрешающей лицензией.