Skip to content

直接内存

1. 为何使用直接内存

直接内存(Direct Memory)并不在《Java虚拟机规范》中存在,所以并不属于Java运行时的内存区域。在JDK 1.4中引入了NIO机制,使用了直接内存,主要为了解决以下两个问题:

  1. Java堆中的对象如果不再使用要回收,回收时会影响对象的创建和使用。
  2. IO操作比如读文件流程,由于借助操作系统的读写功能,需要先把文件读入直接内存(缓冲区)再把数据复制到Java堆中。

对于IO操作如果在JDK中直接使用直接内存,就减少了复制操作:
Alt text 另外在JDK1.8中直接内存还用于保存元空间的数据。

2. 创建直接内存

要创建直接内存上的数据,可以使用ByteBuffer。
语法:ByteBuffer directBuffer = ByteBuffer.allocateDirect(size);
arthas的memory命令可以查看直接内存大小,属性名direct。
Alt text
使用完毕需要释放:

java
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);  
try {  
    // 使用buffer进行操作  
} finally {  
    buffer.clear();  
    // 可以手动触发垃圾回收,但不保证立即生效  
    System.gc();  
}

2.1 设置最大直接内存大小

java
public class Jvm08 {
    static List<ByteBuffer> list = new ArrayList<>();

    public static void main(String[] args) {
        int count = 0;
        while (true){
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 100);
            list.add(buffer);
            System.out.println(++count);
        }
    }
}

可以看到一直申请直接内存,最后会执行报错,说明并不是无休止的申请都是可以的,JVM里面明显是有申请的上限,但交给虚拟机来制定这个上限值是不合理的,因为我们想根据具体不同系统的情况来做定制化的设置,JVM提供直接内存的使用大小参数:
Alt text 如果需要手动调整直接内存的大小,可以使用-XX:MaxDirectMemorySize=大小, 单位k或K表示千字节,m或M表示兆字节,g或G表示千兆字节。默认不设置该参数情况下,JVM自动选择最大分配的大小。