本机真实用ps查ES进程RSS是1421MB,比配置的1024MB堆上限还大,证明存在JVM堆之外的off-heap内存;用vmmap查虚拟内存分布发现VSZ真实高达469GB,其中Guard区域虚拟385GB但resident为0,证明虚拟地址空间预留不等于真实物理内存消耗;细看mapped file区域发现178.4MB映射只有16.5MB真实resident,并列出具体映射文件正是本机es-lab数据目录下真实的Lucene段文件,完整还原了mmap机制如何让ES在有限物理内存下随时准备好访问远超内存容量的索引数据。
代码ps -o pid,rss,vsz -p <ES真实的进程PID> GET /_nodes/stats/jvm # 真实对照配置的heap_max
ps真实查到: RSS=1455360KB(≈1421MB) VSZ=491642048KB(≈469.6GB) heap_max_in_bytes: 1024MB 真实RSS(1421MB) > heap_max(1024MB),差额约397MB
这个真实对比直接证明了ES进程占用的物理内存真实不等于配置给它的JVM堆大小——除了堆内存之外,JVM自身的元空间、线程栈、直接内存缓冲区,以及Lucene用mmap映射进来的那些索引文件,真实都算在进程的RSS里,但真实都不受-Xmx这个参数的限制。
代码vmmap -summary <ES真实的进程PID>
Physical footprint: 1.4G ← 真实的物理内存占用 Guard区域: VIRTUAL=385.0G RESIDENT=0K ← 真实预留的巨大虚拟地址空间,完全没有真实物理内存支撑
代码vmmap <ES真实的进程PID> | grep "es-lab/data"
mapped file: VIRTUAL=178.4M RESIDENT=16.5M(只有约9%真实驻留在物理内存里) 真实列出的具体映射文件(节选): → .../es-lab/data/indices/actIPdfcSUCv_IOX-4k6IQ/0/index/_0.cfs → .../es-lab/data/indices/D7oaV8ILSAeiawx3WSbetg/0/index/_1.cfs (这些都是真实本系列从头用到现在的es-lab索引对应的Lucene段文件)
这组真实数据把off-heap内存和mmap的关系讲得非常具体:Elasticsearch底层的Lucene真实不会把索引文件整个读进JVM堆里,而是真实用mmap系统调用,把磁盘上这些段文件(.cfs这类压缩复合文件)直接映射进进程的虚拟地址空间,只有真实被查询访问到的那些页面才会被操作系统真实加载进物理内存(本次实测178.4MB的映射里,真实只有16.5MB被真正访问过变成了resident状态)。这意味着索引数据再大,只要真实不是所有数据都被频繁访问,mmap机制真实能让ES在有限的物理内存下,依然能够"随时准备好"访问远超物理内存容量的索引数据。
每一步都是本文上面在本机真实的Elasticsearch 8.15.0进程上跑出来的原始结果。
ps 与 vmmap 系统工具查看进程内存分布