java 堆外内存 查看_超干货!Cassandra Java堆外内存排查经历全记录

在上线Cassandra过程中,遇到8G ECS在压测时触发OOM Killer。尽管预留了足够的Java堆内存,但堆外内存使用超出预期。通过调查,发现大量mmap的Cassandra数据文件导致虚拟内存高,且物理内存增长。读取mmap文件时,major page faults上升,证实问题在于数据加载到内存。原因在于Cassandra在64位系统上默认使用mmap,但在小规格ECS中不适用。解决方案包括调整heap配置或关闭mmap特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测。压测时候比较容易触发OOM Killer,把cassandra进程干掉。问题是8G这个规格我配置的heap(Xmx)并不高(约6.5g)已经留出了足够的空间给系统。只有可能是Java堆外内存使用超出预期,导致RES增加,才可能触发OOM。

调查过程

初步怀疑是哪里有DirectBuffer泄漏,或者JNI库的问题。按惯例通过googleperftools追踪堆外内存开销,但是并未发现明显的异常。然后用Java NMT看了一下,也没有发现什么异常。

e277b69ba9363f6416639d67aa7aaca5.png

查到这里思路似乎断了,因为跟DirectBuffer似乎没啥关系。这时候我注意到进程虚拟内存非常高,已经超过ECS内存了。怀疑这里有些问题。

cc4b4889fbaf274ffe22379d1c635f2a.png

进一步通过/proc/pid/smaps查看进程内存地址空间分布,发现有大量mmap的文件。这些文件是cassandra的数据文件。

f1fcdf0ed7ef04d0c4debc2175182c7d.png

此时这些mmap file 虚拟内存是2G,但是物理内存是0(因为我之前重启过,调低过内存防止进程挂掉影响问题排查)。

显然mmap的内存开销是不受JVM heap控制的,也就是堆外内存。如果mmap的文件数据被从磁盘load进物理内存(RES增加),Java NMT和google perftool是无法感知的,这是kernel的调度过程。

考虑到是在压测时候出现问题的,所以我只要读一下这些文件,观察下RES是否会增加,增加多少,为啥增加,就能推断问题是不是在这里。通过下面的命令简单读一下之前导入的数据。

e03cc89c61715baba665422c294d52d0.png

可以观察到压测期间(sar -B),majorpagefault是明显上升的,因为数据被实际从磁盘被load进内存。

7c7440b5aeab9c064429e4b4fda9aa6e.png

同时观察到mmapfile物理内存增加到20MB:

46f452b7b0b8b66f0e9c8aace3b1846d.png

最终进程RES涨到7.1g左右,增加了大约600M:

ef738fbee6626574e114dc65c2aec1cb.png

如果加大压力(50线程),还会涨,每个mmap file物理内存会从20MB,涨到40MB

7.Root cause是cassandra识别系统是64还是32来确定要不要用mmap,ECS都是64,但是实际上小规格ECS内存并不多。

30bd8880b940c7e1d14929ad1d78609b.png

结论

问题诱因是mmap到内存开销没有考虑进去,具体调整方法有很多。可以针对小规格ECS降低heap配置或者关闭mmap特性(disk_access_mode=standard)排查Java堆外内存还是比较麻烦的,推荐先用NMT查查,用起来比较简单,配置JVM参数即可,可以看到内存申请情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值