JVM - 直接内存

# JVM - 直接内存

JDK版本:1.8

# 1、直接内存(Direct Memory)

​ 直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。但是这部分内存也会被频繁地使用,而且也会导致OutOfMemeory异常。

​ 在JDK 1.4版本中引入了NIO类,引入了一种基于通道(Channel)于缓冲区(Buffer)的I/O方式,它可以直接调用Native函数分配堆外内存空间,然后通过存储在堆中的DirectByteBuffer对象作为这块空间的引用以此来对其进行操作。这样就避开了JVM于操作系统之间的内存屏障,减少了在Java堆与Native堆中进行来回复制的额外开销,在某些场景中可以显著提高性能。同时访问直接内存的速度也会优于Java堆,即读写性能高。

​ 本机直接内存的分配是不会受到JVM堆内存大小的限制,但是它还是会受到本机总内存(包括物理内存,SWAP分区或者分页文件)的大小以及处理器寻址空间的限制。一般在配置虚拟机参数时,会根据实际内存设置-Xmx等参数信息,但经常忽略掉直接内存,使得各个内存区域总和大于物理内存限制(包括物理和操作系统级的限制),从而导致动态进行扩展时出现OutOfMemory异常。

​ 也正是因为直接内存不是虚拟机运行时数据区的一部分,直接内存不受JVM内存回收管理,所以其分配回收成本也较高。直接内存大小可通过MaxDirectMemorySize选项进行配置,如果不进行指定默认与堆空间的-Xmx参数值保持一致。

# 2、直接内存与非直接内存差异

使用非直接内存进行IO读写文件时,需要与物理磁盘进行交互。在执行读写操作时,JVMOS直接存在内存屏障,所以进行数据的交互时就会进行来回复制。换而言之就是需要由用户态切换到内核态,内核态中需要同时维护两份重复数据,这样带来的额外性能开销是非常大的。

如下为非直接内存JVMOS之间的数据交互图:

JVM - 直接内存

使用直接内存进行IO读写文件时,直接调用Native函数分配堆外内存空间,并且这部分内存可以通过存储在堆中的DirectByteBuffer对象对其进行操作,避免了内存屏障同时也只需要维护一份数据。避免了不必要的性能开销。

如下为直接内存JVMOS之间的数据交互图:

JVM - 直接内存


GitHub源码地址https://github.com/kapbc/Java-Kapcb/tree/master/src/main/java/com/kapcb/ccc/jvm

备注:此文为笔者学习JVM的笔记,鉴于本人技术有限,文中难免出现一些错误,感谢大家批评指正。

更多Java技术笔记可扫码关注下方微信公众号。

JVM - 直接内存

上一篇:JVM之java对象内存布局(四)


下一篇:JVM