使用 sun.misc.Unsafe? 强制释放直接 ByteBuffer 已分配的本机内存的示例
JDK 提供了分配所谓的直接 ByteBuffers 的能力,其中内存在 Java 堆之外分配.这可能是有益的,因为垃圾收集器不会触及此内存,因此不会增加 GC 开销:这对于缓存等长寿命事物的属性非常有用.
JDK provides abillity to allocate so-called direct ByteBuffers, where memory is allocate outside of Java heap. This can be beneficial since this memory is not touched by garbage collector, and as such does not contribute to GC overhead: this is a very useful for property for long-living things like caches.
然而,现有实现存在一个关键问题:只有在对拥有的 ByteBuffer 进行垃圾回收时才异步分配底层内存;没有办法强制提前释放.这可能会产生问题,因为 GC 周期本身不受 ByteBuffers 处理的影响,并且考虑到 ByteBuffers 可能驻留在旧代内存区域中,可能会在 ByteBuffer 不再使用数小时后调用 GC.
However, there is one critical problem with existing implementation: underlying memory is only allocated asynchronously when the owning ByteBuffer is garbage-collected; there is no way to force early deallocation. This can be problematic since GC cycle itself is not influenced by handling of ByteBuffers, and given that ByteBuffers are likely to reside in Old Generation memory area, it is possible that GC is called hours after ByteBuffer is no longer in use.
但理论上应该可以直接使用 sun.misc.Unsafe
方法(freeMemory、allocateMemory):这是 JDK 本身用于分配/释放本机内存的方法.查看代码,我看到的一个潜在问题是内存双重释放的可能性——所以我想确保正确清理状态.
But in theory it should be possible to use sun.misc.Unsafe
methods (freeMemory, allocateMemory) directly: this is what JDK itself uses for allocating/deallocating native memory.
Looking at code, one potential concern I see is possibility of double-freeing of memory -- so I would want to make sure that state would be properly cleaned.
谁能指点我这样做的代码?理想情况下希望使用它而不是 JNA.
Can anyone point me to code that does this? Ideally would want to use this instead of JNA.
注意:我看到 这个问题有点相关.
NOTE: I saw this question which is sort of related.
看起来指出的答案是好方法:here 是来自 Elastic Search 的代码示例,它使用了这个想法.谢谢大家!
Looks like the answers pointed out are good way to go: here is code example from Elastic Search that uses the idea. Thanks everyon!
推荐答案
使用 sun.misc.Unsafe
几乎不可能,因为分配的本机内存的基地址是 java 的局部变量.nio.DirectByteBuffer
构造函数.
Using sun.misc.Unsafe
is hardly possible because base address of the allocated native memory is a local variable of java.nio.DirectByteBuffer
constructor.
其实你可以用下面的代码强制释放本机内存:
Actually you can force freeing of native memory with the following code:
import sun.misc.Cleaner;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
...
public static void main(String[] args) throws Exception {
ByteBuffer direct = ByteBuffer.allocateDirect(1024);
Field cleanerField = direct.getClass().getDeclaredField("cleaner");
cleanerField.setAccessible(true);
Cleaner cleaner = (Cleaner) cleanerField.get(direct);
cleaner.clean();
}
相关文章