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

Sta*_*Man 21 java memory garbage-collection memory-management

JDK提供了分配所谓的直接ByteBuffers的能力,其中内存在Java堆之外分配.这可能是有益的,因为垃圾收集器不会触及这个内存,因此不会导致GC开销:这对于像缓存这样的长期存在的东西来说非常有用.

但是,现有实现存在一个关键问题:当拥有ByteBuffer被垃圾收集时,底层内存只是异步分配; 没有办法强迫早期解除分配.这可能有问题,因为GC循环本身不受ByteBuffers处理的影响,并且假设ByteBuffers可能驻留在Old Generation内存区域,则可能在ByteBuffer不再使用后几小时调用GC.

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

任何人都可以指向我这样做的代码吗?理想情况下,想要使用它而不是JNA.

注意:我看到这个问题有点相关.

看起来指出的答案是很好的方法:这里是使用这个想法的Elastic Search的代码示例.谢谢大家!

Pet*_*rey 25

有一种更简单的清理内存的方法.

public static void clean(ByteBuffer bb) {
    if(bb == null) return;
    Cleaner cleaner = ((DirectBuffer) bb).cleaner();
    if (cleaner != null) cleaner.clean();
}
Run Code Online (Sandbox Code Playgroud)

如果你相当快地丢弃直接或内存映射的ByteBuffer,使用它可以产生很大的不同.

使用Cleaner执行此操作的原因之一是您可以拥有底层内存资源的多个副本,例如slice().清洁工具有这些资源数量.

  • 也许为了弥补这一点,Java 9 中的“sun.misc.Unsafe”添加了“void invokeCleaner(ByteBuffer)”方法。 (3认同)
  • sun.nio.ch.DirectBuffer(与sun.misc.Cleaner不同)在Java 1.9中默认不能再使用,请参阅JEP 260. (2认同)

szh*_*hem 5

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();
}
Run Code Online (Sandbox Code Playgroud)