ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JVM调优 - 用Arthas解决OOM问题

2021-06-03 13:02:27  阅读:1230  来源: 互联网

标签:查看 OOM 回收 调优 GC 内存 JVM 线程


上一篇:JVM调优 - 理解GC
接上一篇理解GC后,这一篇我们将讲解如何生产调优,或者说生产性能问题排查。

这一篇我们比较偏实际运用,就不过多去讲解一些原生指令或者java visualVm工具了。

java visualVm可以用于自己本地使用,或者测试环境调试,但是生产环境是不适用的,一是生产服务器基本不可能安装这个,二是本地连接进生产查看基本不可能,增加了网络安全风险。

所以我们这次主要讲一讲如何主要用Arthas做生产性能问题定位,并进行更新。

OOM

OOM是最常见的问题,如果FGC无法回收内存时,就会OOM了,有时可能不会引起注意,或者加大一下内存来解决,但是如果我们不去看看引起OOM的具体原因,可能很快又会发生OOM,或者依然会频繁FGC,FGC的STW是会比较久一些的,那么极端情况甚至可能引起微服务调用链路上的一系列超时甚至雪崩。

如何模拟OOM

我们不建议你在启动内存设置太小来模拟OOM,这样可能看不出太多东西。
OOM是怎么产生的?老年代被塞满了无法被回收,所以我们写一个循环,不停去创建新对象并让其被引用,使其不会被GC回收,这样我们就可以看到如何从eden到survivor到old,如何一个一个被填满。

使用Arthas

两个前置工作:

  1. 生产环境打开 HeapDumpOnOutOfMemoryError;
  2. 下载arthas;

我们不再去做arthas的介绍及安装讲解,这个大家可以去看官网,下载跑起来就可以。

用arthas关联到我们的目标项目后,使用如下命令:

dashboard

在这里可以看到:

  • 显示进程内线程
  • 线程组
  • 优先级
  • 消耗资源

在这里我们可以看到消耗资源最多的线程编号,然后可以看看该线程的细节:

thread 线程号

查看该进程内该线程具体信息,不过这里可能不一定需要查看这个,可以直接查看GC的日志,从GC日志进行分析,或者把GC信息dump出来(如果线上流量较大,最好将这台服务的流量断开),拿到本地或测试环境进行分析。

heapdump 目录地址

用上面的arthas命令相当于

jmap -dump:format=b,file=dump.prof 进程号

这个文件在本地有不少工具可以分析,如果dump出的文件较大,可以使用MAT进行线上分析。

我们通过GC日志找到是哪里引起的OOM后,可进行生产文件查看,使用以下命令:

sc -d 报错类

可以看到报错类的更多相关信息。

OOM主要原因

我们可以在dashboard里看到各堆内存区的使用情况,是确实流量太大应该加大内存还是大对象太多占满了老年代?

排查大对象

首先我们先根据文件信息看看是否业务逻辑写的有问题,生成了大量不合理的大对象。

如果是这个原因,我们可以修改代码后,做一下压测或者流量还原,内存使用明显下降或者FGC减少,那么说明修改有效。

并发较大

还有一种情况我们会看到survior区可能内容并不多,但是老年代上升很快,综合业务分析我们的对象大小以及每个对象的大概生存时间,有可能是该对象在扫描时还有被引用因此会从eden进入survior区,但是survior区不够大,因此直接进入了老年代,而下次GC时,该对象无法被回收,现象与上面有点像,但是处理上会有些不同。

这里的对象大小是何理的,因此我们的做法是加大新生代的内存大小,这样让该对象能够进入survior区,并在GC时能被回收。

加大新生代即可?

不进入老年代,都在新生代GC是不是就能提升性能呢?如果是这样为什么还要去做分代,并且老年代默认更大呢?

新生代GC依然会触发STW,如果新生代空间大了,其扫描一样会耗时较久,也会降低性能。

当然现在的CMS、G1等并发低延时垃圾回收器,针对大内存会有更好的GC性能表现,但也不是一味上新的垃圾回收器就是好的,这里强调了大内存,而并发垃圾回收也意味着其对CPU的性能消耗会提升,还是要根据实际情况使用。

其它实用指令

thread -b
查看是否有线程死锁

jad 类
查看代码还原
查看引用类

使用该命令可以看看生产环境实际的类文件内容,有时有些问题确实是因为生产环境文件版本不正确导致的。

redifine 类文件
热替换
生产救急用

这个命令可直接热替换生产环境使用的文件,但是注意不要修改类名、方法名等。

为什么用这个命令更新后就能直接生效?因为他实际修改的是已经加载到内存的内容。

trace 类型 方法名
追踪其执行链路执行时间

这个对于定位慢执行很有用,不用再自己去打日志统计时间,而且自己打印日志统计时间也不是很便于查看调用链路上的每个调用的执行时间,用这个命令就会比较方便。

// 查看该方法的入参出参异常
watch 全路径类名 方法名 “{params,returnObj,throwExp}” -x 3
// 回放刚才的请求
tt -t 类名 方法名 || tt -i 序列号(可通过watch查看) -w “target.方法”

通过上述组合指令,可以还原线上的某次请求,用于进行问题排查与定位。

下一篇:解决CPU占用高问题

标签:查看,OOM,回收,调优,GC,内存,JVM,线程
来源: https://blog.csdn.net/weixin_42288219/article/details/117486578

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有