使用sun.misc.Unsafe?强制释放直接由ByteBuffer分配的本地内存的示例?


问题内容

JDK提供了分配所谓的直接ByteBuffer的能力,其中内存是在Java堆之外分配的。这可能是有益的,因为该内存不会被垃圾收集器占用,因此不会增加GC开销:这对于诸如缓存之类的长期存在的属性非常有用。

但是,现有实现存在一个关键问题:仅当拥有的ByteBuffer被垃圾回收时,底层内存才被异步分配;没有办法强制提前解除分配。这可能是有问题的,因为GC周期本身不受ByteBuffer的处理的影响,并且考虑到ByteBuffer可能位于旧一代内存区域中,因此有可能在ByteBuffer不再使用后数小时调用了GC。

但是从理论上讲,应该可以直接使用sun.misc.Unsafe方法(freeMemory,allocateMemory):这是JDK本身用于分配/取消分配本机内存的方法。查看代码时,我看到的一个潜在问题是可能会双重释放内存-
因此,我想确保可以正确清除状态。

谁能指出我这样做的代码?理想情况下,将要使用它代替JNA。

看起来指出的答案是个不错的方法:是Elastic
Search中使用该想法的代码示例。谢谢大家!


问题答案:

sun.misc.Unsafe由于分配的本机内存的基址是java.nio.DirectByteBuffer构造函数的局部变量,因此使用几乎是不可能的。

实际上,您可以使用以下代码强制释放本机内存:

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();
}