在 Java 中为 JOGL 释放直接缓冲本机内存 [英] Deallocating Direct Buffer Native Memory in Java for JOGL

查看:38
本文介绍了在 Java 中为 JOGL 释放直接缓冲本机内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用直接缓冲区 (java.nio) 来存储 JOGL 的顶点信息.这些缓冲区很大,在应用程序生命周期中会被多次更换.内存没有及时释放,我在几次更换后内存不足.

I am using direct buffers (java.nio) to store vertex information for JOGL. These buffers are large, and they are replaced several times during the application life. The memory is not deallocated in time and I am running out of memory after a few replacements.

似乎没有使用 java.nio 的缓冲区类来解除分配的好方法.我的问题是:

It seems that there is not good way to deallocate using java.nio's buffer classes. My question is this:

JOGL 中是否有删除直接缓冲区的方法?我正在研究 glDeleteBuffer(),但似乎这只会从视频卡内存中删除缓冲区.

Is there some method in JOGL to delete Direct Buffers? I am looking into glDeleteBuffer(), but it seems like this only deletes the buffer from the video card memory.

谢谢

推荐答案

直接 NIO 缓冲区使用非托管内存.这意味着它们是在本机堆上分配的,而不是在 Java 堆上.因此,只有当 JVM 用完 Java 堆上的内存时才会释放它们,而不是本机堆上的内存.换句话说,它是不受管理的 = 由您来管理它们.不鼓励强制进行垃圾回收,并且大多数情况下无法解决此问题.

The direct NIO buffers use unmanaged memory. It means that they are allocated on the native heap, not on the Java heap. As a consequence, they are freed only when the JVM runs out of memory on the Java heap, not on the native heap. In other terms, it's unmanaged = it's up to you to manage them. Forcing the garbage collection is discouraged and won't solve this problem most of the time.

当你知道一个直接的 NIO 缓冲区对你来说已经无用时,你必须通过使用它的 sun.misc.Cleaner(StaxMan 是对的)释放它的原生内存并调用 clean()(Apache Harmony 除外),调用free()(使用 Apache Harmony)或使用更好的公共 API 来做到这一点(也许在 Java > 12 中,扩展 AutoCloseable 的 AutoCleaning?).

When you know that a direct NIO buffer has become useless for you, you have to release its native memory by using its sun.misc.Cleaner (StaxMan is right) and call clean() (except with Apache Harmony), call free() (with Apache Harmony) or use a better public API to do that (maybe in Java > 12, AutoCleaning that extends AutoCloseable?).

这不是 JOGL 的工作,您可以使用纯 Java 代码自己完成.我的例子 在 GPL v2 和 这个例子是在一个更宽松的许可之下.

It's not JOGL job to do that, you can use plain Java code to do it yourself. My example is under GPL v2 and this example is under a more permissive license.

我的最新示例 甚至适用于 Java 1.9,并支持 OpenJDK、Oracle Java、Sun Java、Apache Harmony、GNU Classpath 和 Android.您可能需要删除一些语法糖才能使其与 Java < 一起使用.1.7(多捕获、菱形和泛型).

Edit.: My latest example works even with Java 1.9 and supports OpenJDK, Oracle Java, Sun Java, Apache Harmony, GNU Classpath and Android. You might have to remove some syntactical sugar to make it work with Java < 1.7 (the multi catches, the diamonds and the generics).

参考:http://www.ibm.com/developerworks/图书馆/j-nativememory-linux/

Direct ByteBuffer 对象会自动清理它们的原生缓冲区但只能作为 Java 堆 GC 的一部分这样做——所以他们不会自动响应本地堆上的压力.GC 只发生当 Java 堆变得如此满时,它无法为堆分配提供服务请求或者如果 Java 应用程序显式请求它(不是推荐,因为它会导致性能问题).

Direct ByteBuffer objects clean up their native buffers automatically but can only do so as part of Java heap GC — so they do not automatically respond to pressure on the native heap. GC occurs only when the Java heap becomes so full it can't service a heap-allocation request or if the Java application explicitly requests it (not recommended because it causes performance problems).

参考:http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#direct

直接缓冲区的内容可能驻留在普通垃圾收集堆之外

The contents of direct buffers may reside outside of the normal garbage-collected heap

此解决方案已集成在 Java 14 中:

This solution is integrated in Java 14:

try (MemorySegment segment = MemorySegment.allocateNative(100)) {
   ...
}

您可以通过调用 MemorySegment.ofByteBuffer(ByteBuffer),在Java 16:

You can wrap a byte buffer into a memory segment by calling MemorySegment.ofByteBuffer(ByteBuffer), get its memory address and free it (this is a restricted method) in Java 16:

CLinker.getInstance().freeMemoryRestricted(MemorySegment.ofByteBuffer(myByteBuffer).address());

请注意,您仍然需要在许多非平凡情况下使用反射来找到可以释放的缓冲区,通常是当您的直接 NIO 缓冲区不是 ByteBuffer 时.

Note that you still need to use reflection in many non trivial cases in order to find the buffer that can be deallocated, typically when your direct NIO buffer isn't a ByteBuffer.

注意:sun.misc.Cleaner 已移入jdk.internal.ref.Cleaner 在 Java 1.9 中的模块java.base"中,后者在短时间内实现了 java.lang.Runnable(感谢 Alan Bateman 提醒我这种差异)但是 不再是这种情况.你必须调用 sun.misc.Unsafe.invokeCleaner(),它是 在 JogAmp 的 Gluegen 中完成.我更喜欢使用 Cleaner 作为 Runnable,因为它避免了依赖 sun.misc.Unsafe 但它现在不起作用.

N.B: sun.misc.Cleaner has been moved into jdk.internal.ref.Cleaner in Java 1.9 in the module "java.base", the latter implemented java.lang.Runnable (thanks to Alan Bateman for reminding me that difference) for a short time but it's no longer the case. You have to call sun.misc.Unsafe.invokeCleaner(), it's done in JogAmp's Gluegen. I preferred using the Cleaner as a Runnable as it avoided to rely on sun.misc.Unsafe but it doesn't work now.

我的最后一个建议适用于 Java 9、10、11 和 12.

My last suggestion works with Java 9, 10, 11 and 12.

我的最新的示例需要使用孵化功能(需要 Java >= 14),但非常非常简单.

My very latest example requires the use of an incubated feature (requires Java >= 14) but is very very simple.

Lucene 中的一个很好的例子 在更宽松的许可下.

There is a good example in Lucene under a more permissive license.

这篇关于在 Java 中为 JOGL 释放直接缓冲本机内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆