直接内存读写快于堆内存,本质是物理寻址路径更短、cpu参与更少、彻底消除跨域拷贝:它通过mmap分配物理连续内存并建立用户/内核双映射,绕过多级页表查表与oop解压,支持零拷贝dma传输,且不受gc移动影响,缓存行友好、tlb局部性更优。

堆外直接内存读写速度优于堆内内存,本质不在“内存位置远近”,而在物理寻址路径更短、CPU参与更少、跨域拷贝彻底消失。从物理寻址视角看,关键差异体现在地址翻译层级、内存访问通路和I/O数据流三方面。
物理地址连续性 + 双重虚拟映射,绕过页表遍历开销
直接内存由JVM通过mmap或malloc向OS申请物理地址连续的内存块,并由内核建立用户态与内核态两套虚拟地址映射,指向同一段物理页帧:
- 堆内内存:每次访问需经JVM对象头→压缩OOP解压→堆内偏移计算→多级页表查表(TLB未命中时触发多次内存访存)→最终定位物理地址
- 直接内存:
DirectByteBuffer.address字段直接保存该内存块起始物理地址的映射虚拟地址;CPU加载指令后,仅需一次TLB命中即可完成线性地址→物理地址转换,无OOP解压、无对象头跳转、无堆内边界检查开销
零拷贝链路:数据不穿越用户/内核边界
传统堆内IO必须经历“用户态缓冲区 → 内核态socket缓冲区”的显式复制(如write()调用);而直接内存让这一过程失效:
- 应用往
DirectByteBuffer写入数据,即直接写入物理内存中被内核映射的那一份 - 当调用
channel.write(buffer),底层sendfile或splice可直接让网卡DMA控制器或协议栈从该物理地址取数,无需CPU搬运、无需额外缓存副本 - 堆内Buffer则必须先由JVM把
byte[]内容memcpy到内核空间——这一步在物理寻址层面体现为两次独立内存访问(源物理页+目标物理页),且强制占用CPU周期
缓存行友好 + 无GC干扰的稳定物理布局
物理连续性带来底层硬件级优势:
- DMA传输天然要求物理连续内存;堆外分配满足此约束,单次DMA可覆盖大块缓存行,减少总线事务次数
- 堆内对象受GC移动影响,即使初始连续,后续可能被复制到其他物理页,导致相同逻辑数据散落在不同DRAM bank,加剧内存访问延迟
- 直接内存不受GC暂停干扰,物理地址生命周期稳定,CPU预取器与TLB局部性更可靠,缓存命中率更高
说到底,快不是因为“堆外”这个标签,而是因为它把原本横跨用户态/内核态、软件层/硬件层、逻辑地址/物理地址的四重寻址与搬运,压缩成一条直达物理DRAM的确定性通路。










