主题切换
直接内存(堆外内存)
一、基础定义
- 归属:不属于JVM运行时五大内存区,属于操作系统本地堆外内存,不受JVM直接管理;
- 使用场景:Java NIO的
DirectByteBuffer,用作IO读写缓冲区; - 特性:读写性能高,但内存分配、回收开销大;
- 溢出异常:堆外内存耗尽抛出
java.lang.OutOfMemoryError: Direct buffer memory。
二、常规IO vs NIO直接内存 文件拷贝流程对比
1. 传统IO(堆缓冲区byte[])两次拷贝
- 磁盘数据 → 操作系统内核缓冲区(内核态)
- 内核缓冲区 → Java堆byte[]缓冲区(用户态,第一次拷贝)
- Java堆缓冲区 → 内核缓冲区(第二次拷贝)
- 内核缓冲区 → 目标磁盘文件 问题:存在两次用户态与内核态之间的数据拷贝,性能损耗大。
2. NIO直接内存(DirectBuffer)一次拷贝
- 磁盘数据 → 直接内存缓冲区(堆外系统内存)
- 直接内存缓冲区直接与内核交互,省去Java堆中转拷贝 仅一次数据拷贝,减少CPU上下文切换与内存复制开销,大文件/高并发IO场景性能大幅提升。
三、优缺点
优点
- 减少内存拷贝次数,IO读写速度更快;
- 不占用Java堆空间,缓解堆内存压力;
- Netty、SpringCloud等框架底层大量使用直接内存优化网络IO。
缺点
- 分配、回收堆外内存成本高,频繁创建销毁会损耗性能;
- 不受JVM GC直接管控,若不手动释放,容易堆外内存泄漏、OOM;
- 可通过JVM参数
-XX:MaxDirectMemorySize限制最大直接内存容量。
四、面试简答
问:什么是直接内存?有什么作用?
答: 直接内存是操作系统堆外本地内存,不属于JVM标准运行时内存,不受JVM直接管理,主要用于NIO的DirectByteBuffer缓冲区。 传统文件IO需要在内核缓冲区和Java堆数组之间两次拷贝,性能差;使用直接内存可以跳过堆缓冲区,数据直接在内核与堆外内存传输,减少一次拷贝,提升IO读写性能。 缺点是分配回收开销大,需控制大小,超出限制会抛出Direct buffer memory类型OOM。