线上应用程序OOM排查示例

问题:实际占用内存远大于分配内存,无OOM

服务器:120.133.0.233, 实例:api-gateway-analyze

1、查找问题进程

top , shfit + M 让程序按照内存占用大小排序

查看当前进程分配的实际内存大小

2、初步排查问题

回忆JVM内存构成,在JDK8版本,主要由Heap + Other(Metaspace + JVM运行所需其他),参考:好图收藏

按照以上思路猜测为Metaspace超出限制

命令:jstat -gc 104144 1000 3

结果很遗憾,meta占用空间只有几十M

3、开启NMT排查

实例启动时加上 -XX:NativeMemoryTracking=detail 参数

执行:jcmd 104144 VM.native_memory summary

简单分析各组件占用内存大小:Symbol过于显眼,占用高达1.8G。

使用以下组合命令可以设计基准点,过一段时间再执行,查看每个模块的增长量

jcmd 104144 VM.native_memory baseline

jcmd 104144 VM.native_memory summary.diff

目前问题锁定,Symbol原因

4、Symbols中存储说明

    让我们从字符串开始,它是应用程序和库代码中最常用的数据类型之一。由于它们无处不在,因此它们通常占据堆的很大一部分。

如果大量的这些字符串包含相同的内容,则将浪费堆的很大一部分。为了节省一些堆空间,我们可以存储每个String的一个版本,

并使其他版本引用存储的版本。此过程称为String Interning。

    由于JVM只能内生编译时间字符串常量,因此我们可以对要内生的字符串手动调用String.intern()方法。JVM将内部字符串存储在称

为字符串表(也称为字符串池)的特殊本地固定大小的哈希表中。我们可以通过-XX:StringTableSize调整标志来配置表的大小(即存储桶数)。

除了字符串表之外,还有另一个本机数据区域,称为运行时常量池。JVM使用此池存储必须在运行时解析的常量,如编译时数字文字,方法和字段引用。

5、解决方案

解决方案:增加-XX:StringTableSize参数配置

问题点:网关分析为了提高并发,对用户的ip地址、uid等属性大量使用intern()方法,这样会让大量的不重复的信息写入常量池中,不会占用heap内存,也不会OOM。对于同一服务器下的其他应用是一种灾难。

6、其他手段

1、查看进程内存占用

ps -p 104144 -o rss,vsz

2、进程内存分配(倒序)

pmap -x 104144  | sort -n -k3

3、gdb来dump内存并查看

1、gdb attach 104144

2、dump memory a.dump 0x7f8f20000000 0x7f8f2c000000

3、view a.dump

参考文章

【Native Memory Tracking in JVM】Native Memory Tracking in JVM | Baeldung

【JVM内存非典型术语介绍】JVM内存非典型术语介绍(shallow/retained/rss/reserved/committed) - 简书

【Java堆外内存增长问题排查】Java堆外内存增长问题排查-CSDN博客

【Java堆外问题小结】JAVA堆外内存排查小结 - 知乎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诚信赢天下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值