Vertx3.9.8程序内存持续增长,Internal内存不断上涨问题排查咨询
问题根因定位方向
你观测到的NMT Internal内存上涨,首先明确两个基础事实:
- JDK 8及更低版本中,
ByteBuffer.allocateDirect()分配的堆外内存,全部统计在NMT的Internal分类下,不需要你手动写堆外分配代码,依赖框架底层自动分配的堆外也会算在这里 - 你提供的启动脚本存在严重的参数顺序错误,这是首要排查项
第一步:先修正启动脚本错误
你当前的启动命令中JVM参数和程序参数顺序完全混乱,核心错误点如下:
- 所有JVM参数(
-Xms/-Xmx/-XX开头的参数、-javaagent、-D开头的系统属性)必须放在-jar参数的前面,放在-jar后面的参数会被当成程序运行参数,不会被JVM识别,你配置的4G堆内存当前完全没生效 - 命令中
start-Dvertx-id=server缺少空格,应该为start -Dvertx-id=server - 你配置了两个不同的fat jar作为javaagent,需要确认是否是必要配置,多余的javaagent很容易引发内存泄漏
修正后的启动脚本参考:
su web -s /bin/bash -c "/usr/bin/nohup /usr/bin/java -XX:NativeMemoryTracking=detail -Xms4G -Xmx4G -XX:-OmitStackTraceInFastThrow -XX:MaxDirectMemorySize=2G -javaagent:../target/showbiz-server-game-1.0-SNAPSHOT-fat.jar -javaagent:../../quasar-core-0.8.0.jar=b -Dvertx.hazelcast.config=/data/appdata/webdata/Project/config/cluster.xml -Dlog4j.configurationFile=log4j2_logstash.xml -jar ../target/server-1.0-SNAPSHOT-fat.jar start -Dvertx-id=server -conf application-conf.json -cluster >nohup.out 2>&1 &"
注意新增了-XX:MaxDirectMemorySize=2G参数,限制堆外内存上限,方便后续排查时快速复现OOM定位泄漏源。
第二步:框架层面排查
修正启动参数后如果内存仍持续上涨,按以下顺序排查:
1. 排除Quasar协程兼容问题
Quasar 0.8.0版本较老,和Vertx 3.9.8存在已知的兼容问题,可能导致协程关联的堆外缓冲区无法释放:
- 临时去掉
-javaagent:../../quasar-core-0.8.0.jar=b参数,运行程序观测Internal内存变化,如果不再上涨,直接确认是Quasar的问题,可升级到Quasar最新兼容版本,或改用Vertx原生的Future/Promise异步模型替代协程。
2. 排除Hazelcast集群泄漏问题
Vertx 3.9.8默认适配的Hazelcast版本为3.12.x,如果你使用了不匹配的Hazelcast版本,很容易出现集群通信缓冲区泄漏:
- 先禁用集群模式运行单机版本程序,如果内存不再上涨,确认是集群相关问题:
- 检查你所用的Hazelcast版本是否和Vertx 3.9.8适配
- 检查
cluster.xml配置,是否存在连接超时时间过长、心跳包配置错误的问题 - 排查代码中是否有大量未释放的分布式Map、分布式锁等Hazelcast资源
3. 排除Vertx本身的资源泄漏
检查代码中所有用到Vertx Buffer、HttpClient/WebClient、NetServer的逻辑:
- 有没有大量未关闭的长连接、WebSocket连接
- HttpClient调用后有没有正确结束响应处理器,有没有遗留的未完成的请求回调
- 可升级到Vertx 3.9.16最新补丁版本,修复3.9.8已公开的内存泄漏问题
第三步:精准定位泄漏源
如果以上步骤仍未找到问题,用以下工具定位:
- 用Arthas的
dashboard命令实时观测堆外内存占用变化,用jmap -histo:live <pid>查看是否存在大量未被回收的DirectByteBuffer对象 - 用
jstack排查是否有大量阻塞的Netty IO线程,IO线程阻塞会导致关联的缓冲区无法被回收
内容的提问来源于stack exchange,提问作者pumbaa
相关产品推荐
相关产品推荐

