JVM:什么是直接内存(Direct Memory)有什么作用?

你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。

点击下方👇关注公众号,带你一起复习后端技术,看看面试考点,补充积累技术知识,每天都为面试准备积累

文章可能会比较长,主要解析的非常详解,或涉及一些底层知识,供面试高阶难度用。可以根据自己实际理解情况合理取舍阅读


直接内存(Direct Memory) 是 Java 中的一种内存管理方式,它并不属于 JVM 的堆内存或栈内存,而是由操作系统直接分配的内存区域。直接内存通常用于高性能 I/O 操作,像是文件读取、网络通信、NIO(Non-blocking I/O)等场景中,因为它能够绕过 JVM 堆和垃圾回收的管理,从而提高性能。

01
直接内存的定义


直接内存是 Java 程序通过 java.nio.ByteBuffer 类或其他底层 I/O 操作来分配的内存,而不是由 JVM 堆进行管理。直接内存的分配直接依赖于操作系统,因此它不受 JVM 垃圾回收机制的管理。

在传统的 JVM 堆内存中,内存的分配和回收由垃圾回收器负责,而直接内存的分配和回收则完全依赖于操作系统。直接内存是通过 Unsafe 类或 DirectByteBuffer 来管理的,这使得它的使用比普通堆内存更高效。


02
为什么使用直接内存


性能优化:直接内存通常用于高性能计算或 I/O 操作,它减少了 Java 堆和操作系统之间的数据复制,因为直接内存可以直接在 JVM 和操作系统之间传输数据,避免了缓冲区的复制。


大数据处理:一些大数据应用需要更高效的内存使用,直接内存避免了垃圾回收带来的性能开销,尤其是在频繁进行 I/O 操作时。


低延迟需求:在需要低延迟、高吞吐量的应用中(例如高性能网络服务、视频流处理等),直接内存的使用可以减少内存分配和释放的开销,从而提供更低的延迟。


03
如何使用直接内存


Java 提供了 java.nio.ByteBuffer 类来操作直接内存。你可以通过 ByteBuffer.allocateDirect() 方法申请直接内存:

ByteBuffer buffer = ByteBuffer.allocateDirect(1024); // 1KB 直接内存

这将创建一个 1KB 大小的直接内存区域。与普通的堆内存不同,allocateDirect() 方法返回的是直接内存,操作系统会直接为其分配内存,而不是通过 JVM 堆。


04
JVM 参数:MaxDirectMemorySize


虽然直接内存不是由 JVM 堆管理的,但是你仍然可以通过 -XX:MaxDirectMemorySize 参数来限制 Java 应用能够使用的最大直接内存大小。默认情况下,JVM 允许使用的直接内存与堆内存的大小相同,但你可以显式设置它。

-XX:MaxDirectMemorySize=512m

这个参数指定了 JVM 允许使用的最大直接内存为 512MB。当直接内存的使用超出这个限制时,JVM 会抛出 OutOfMemoryError 错误。


05
直接内存与堆内存的区别


管理方式:

  • 堆内存:由 JVM 管理,经过垃圾回收机制进行回收。

  • 直接内存:由操作系统管理,不经过 JVM 垃圾回收机制。


用途:

  • 堆内存:主要用于存储对象数据、引用类型变量等。

  • 直接内存:用于 I/O 操作和高性能计算,如网络通信和文件操作等。


性能:

  • 堆内存:操作相对较慢,因为涉及垃圾回收。

  • 直接内存:操作较快,因为避免了 JVM 和操作系统之间的数据复制。


06
直接内存的应用场景


网络应用:例如使用 NIO(非阻塞 I/O)技术时,网络缓冲区通常是直接内存,以提高网络吞吐量。

文件操作:直接内存可以用于高效的文件读取和写入,尤其是对大文件的处理。

高性能计算:一些高性能的计算应用会使用直接内存来存储计算数据,以避免堆内存的开销。


07
直接内存的限制


内存泄漏问题:由于直接内存不受垃圾回收器的管理,它可能会出现内存泄漏问题。若没有及时释放直接内存,可能会导致程序的内存占用不断增加。

内存碎片:直接内存由操作系统管理,因此它可能会遇到内存碎片问题,尤其是在大量动态分配和释放直接内存的场景中。


08
总结


直接内存是用于提高性能的内存分配方式,它允许 Java 程序绕过 JVM 堆直接访问操作系统内存,常见于高性能 I/O 或大数据处理场景。通过 -XX:MaxDirectMemorySize 设置最大直接内存大小,以避免直接内存的过度使用导致内存溢出。在容器中运行时,直接内存也是受容器内存限制的,过多的直接内存分配可能会导致容器资源耗尽或内存溢出错误。

今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!

END


扫码关注

一起积累后端知识
不积跬步,无以至千里
不积小流,无以成江海

喜欢此内容的人还喜欢

《Java面试题指南》回归啦~


一个阿里二面面试官必问的问题


Lambda表达式说爱你不容易


分享面试:mysql数据库索引失效的情况


Spring-Boot中一个不起眼的好工具StopWatch