前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >经典jvm问题案例分析及处理详解

经典jvm问题案例分析及处理详解

作者头像
IT运维技术圈
发布2023-03-06 09:00:33
7720
发布2023-03-06 09:00:33
举报
文章被收录于专栏:IT运维技术圈

一、线上案例

案例1:线上K8S环境,服务OOM,疯狂FGC,CPU占用100%全为 VM thread

案例2:服务hang住,用户无法登录

二、故障发生时,我们应该做什么

服务器硬件有没有问题,网络、存储、内存、CPU情况有没有问题。如果有普罗米修斯、zabbix监控,可以直接查看监控,如果没有则需要进入服务器进行定位。

1.查看硬盘使用空间,是否有挂载点存满等。

1.1 df -h 命令查看

1.2 TOP 查看目前服务器状态,进程状态,shift+m对使用情况进行排序

1.3 查看内存等情况 free -g 或者free -m

三、定位内存故障后,我们怎么定位,调优java堆内存情况。

1. 查看当前内存大小

代码语言:javascript
复制
jmap -heap pid pid为 可以通过 ps -ef|grep java(或者关键字来查询)

整体内存可以分为堆区和非堆区

堆区:

所有new的对象都在堆区 新生代、中生代、老年代源自于对堆区的细分 Java中每新new一个对象所占用的内存空间就是新生代的空间,当java垃圾回收机制对堆区进行资源回收后,那些新生代中没有被回收的资源将被转移到中生代,中生代的被转移到老生代。-XX:MaxNewSize=518 等是对新生代的最大值进行设置

非堆区:

包括持久带, 用来存放静态文件,如Java类、方法等。

几个参数:

代码语言:javascript
复制
1.堆(Heap)内存分配 -Xms : 初始堆大小 -Xmx: 最大堆大小,可设置为与Xms一样 -XX:NewSize=n:设置年轻代大小 
2.堆(Heap)内存分配 -XpermSize = n -XMaxPermSize = n 注意-XMaxPermSize和-Xmx的总和不能超过物理机的最大内存值

查询结果如下(有些服务可能没有jmap等命令,需要额外安装,或者换docker基础镜像)

代码语言:javascript
复制
Heap Configuration:(MaxHeapSize) = 1004535808 (958.0MB) //最大堆大小,默认为物理内存的1\
4NewSize = 1310720 (1.25MB)MaxNewSize = 17592186044415 MB //64位操作系统理论无限制
OldSize = 5439488 (5.1875MB)NewRatio = 2SurvivorRatio = 8PermSize = 21757952 (20.75MB) //非堆区大小

我们要观察几个参数:

MaxHeapSize,堆内存空间,也是我们最需要关注的。如果JVM没有设置,默认为服务器的1/4,所以看这个参数,就可以大概识别服务器JVM配置是否合理。当堆内存的年轻代进行YGC后,会有一部分对象进入老年代,当老年代满了会进行一次FGC,来再一次回收,如果FGC后依然没有办法回收大量对象,即有内存泄漏OOM。

2. 设置当前内存大小

如果堆内存过小,我们怎么设置呢,调节xms和xms即可

如tomcat配置

代码语言:javascript
复制
JAVA_OPTS="-server -Xms10240M -Xmx10240M -Xss256k -XX:PermSize=128m -XX:MaxPermSize=128m -Xmn512m-Xms:
初始heap大小,使用的最小内存,cpu性能高时,此值应该设置的大一些-Xms:
java heap最大值,使用的最大内存-XX:
PerSize:设定的最大内存的永久保存区域(后面会说)

3. 怎么定位内存的使用情况呢(GC情况)

上述,我们只是通过查询jvm的heap堆内存情况,并结合业务以及服务器参数初步判断内存是否需要调节。那如果我们内存调节后,还是会出现这种情况,怎么办。

这时候我们需要查看内存的YGC 和FGC的情况,以CMS内存回收为例:

YGC: 年轻代内存回收

FGC:老年代内存回收

如果对内存年轻代、老年代回收不太清楚,可以去科普下,但是也可以直接进入如果定位FGC情况。

查看当前jvm gc情况

代码语言:javascript
复制
jstat -gcutil pid 1000(1秒) 20(次)
代码语言:javascript
复制
S0:Survivor0已用内存百分比
S1:Survivor1已用内存百分比
E:eden已用内存百分比
O:老年代已用内存百分比
M:元空间已用内存百分比
CCS:压缩类空间已用内存百分比
YGC:Young GC触发次数 
YGCT:耗时
FGC:Full GC次数
FGCT:耗时
GCT:总耗时

上图可以看到,当前JVM环境,O区老年代快照基本全是100%,也就是老年代已经满了,怎么都回收不掉。快照时间内,FGC已经从245次,增加到了246次,这么短的时间内,就进行来一次FGC,并且内存回收不掉,基本就是OOM了。

当JVM进行FGC的时候,服务的性能是非常低下的,因为JVM要去占用大量CPU去进行内存回收,业务侧看到的就是系统卡,变慢。服务器侧的表现就是CPU飙高。

4. 定位了内存OOM,怎么定位到对象或者代码呢

4.1 jmap查看内存中的对象数目、大小统计直方图

如果能粗略定位到,异常的对象则可以直接定位到相关服务,或者代码。

但是现实往往没那么简单,jmap直方图基本很难看到异常。需要导出内存快照。

4.2导出内存快债dump用工具分析
代码语言:javascript
复制
root@ubuntu:/# jmap -dump:format=b,file=/tmp/dump.dat 21711 
Dumping heap to /tmp/dump.dat ... 
Heap dump file created 
dump出来的文件可以用MAT、VisualVM等工具查看,这里用jhat查看:

关于内存泄漏的分析,可以把dump文件交给开发,或者运维和开发一起定位,本文不在展开,后续会有文章专门分析。

案例1分析:可以见到JVM在疯狂FGC,占用大量CPU。结合jmap查看内存情况,发现项目压根没设置堆内存大小。

案例1优化:调节JVM堆内存,导出内存快照,定位是否有异常地方。

案例2分析:提示java.lang.OutOfMemoryError: PermGen space,故意思意,是非堆区的空间不够。

代码语言:javascript
复制
ps -ef|grep tomcat
jmap -heap 19279
注意到perm Generation使用率已经84%,极有可能是非堆区空间不够用。上面配置也显示分配的默认PermSize为128M。
代码语言:javascript
复制

案例2优化:调节JVM非堆区。杀死服务,调整tomcat参数为

代码语言:javascript
复制
JAVA_OPTS="-server -Xms10240M -Xmx10240M -Xss256k -XX:PermSize=512m -XX:MaxPermSize=512m -Xmn1024m

继续查看堆内存使用情况,可以看到使用率变成17%。应该是起到效果了。

原作者: 追风書翁

源链接:

https://juejin.cn/post/7160871419654438920

编辑:IT运维技术圈

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT运维技术圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、线上案例
    • 案例1:线上K8S环境,服务OOM,疯狂FGC,CPU占用100%全为 VM thread
      • 二、故障发生时,我们应该做什么
        • 三、定位内存故障后,我们怎么定位,调优java堆内存情况。
          • 1. 查看当前内存大小
          • 2. 设置当前内存大小
          • 3. 怎么定位内存的使用情况呢(GC情况)
          • 4. 定位了内存OOM,怎么定位到对象或者代码呢
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档