JVM线上问题排查基本操作

news/2024/11/21 2:32:42/

1. 要解决的问题

CPU 飚高,内存溢出,频繁 GC 

2. CPU 飚高

2.1 定位问题的思路

首先找到 CPU 飚高的那个 Java 进程,因为你的服务器会有多个 JVM 进程。
然后找到那个进程中的 “问题线程”,
最后根据线程堆栈信息找到问题代码。最后对代码进行排查。

2.2 具体操作

1. 通过 top 命令找到 CPU 消耗最高的进程,并记住进程 ID。
2. 再次通过 top -Hp [进程 ID] 找到 CPU 消耗最高的线程 ID,并记住线程 ID.
3. 通过 JDK 提供的 jstack 工具 dump 线程堆栈信息到指定文件中。具体命令:jstack -l [进程 ID] >jstack.log。
4. 由于刚刚的线程 ID 是十进制的,而堆栈信息中的线程 ID 是16进制的,因此我们需要将10进制的转换成16进制的,并用这个线程 ID 在堆栈中查找。使用 printf "%x\n" [十进制数字] ,可以将10进制转换成16进制。
5. 通过刚刚转换的16进制数字从堆栈信息里找到对应的线程堆栈。就可以从该堆栈中看出端倪。

2.3 经验总结

1.  查看是否存在死循环, 根据业务进行修复
2.  C2 编译器执行编译时也会抢占 CPU, 什么是 C2编译器呢?当 Java 某一段代码执行次数超过10000次(默认)后,就会将该段代码从解释执行改为编译执行,也就是编译成机器码以提高速度。而这个 C2编译器就是做这个的。如何解决呢?项目上线后,可以先通过压测工具进行预热,这样,等用户真正访问的时候,C2编译器就不会干扰应用程序了。
3.  GC 线程导致的,那么极有可能是 Full GC ,那么就要进行 GC 的优化

3. 内存问题(内存的问题就是 GC 的问题)排查

3.1 内存溢出

通过加上 -XX:+HeapDumpOnOutOfMemoryError 参数,
该参数作用是:在程序内存溢出时输出 dump 文件,再通过 dump 分析工具进行分析。

参考:JVM离线分析-使用MAT分析dump堆文件

3.2 内存没有溢出,但 GC 不健康(复杂)

a. 通常一个健康的 GC 是什么状态呢?

YGC 5秒一次左右,每次不超过50毫秒,FGC 最好没有,CMS GC 一天一次左右。
b. GC 的优化有2个维度,一是频率,二是时长
1. YGC频率:我们看YGC,首先看频率,如果 YGC 超过5秒一次,甚至更长,说明系统内存过大,应该缩小容量,如果频率很高,说明 Eden 区过小,可以将 Eden 区增大,但整个新生代的容量应该在堆的 30% - 40%之间,eden,from 和 to 的比例应该在 8:1:1左右,这个比例可根据对象晋升的大小进行调整。时长:如果 YGC 时间过长呢?YGC 有2个过程,一个是扫描,一个是复制,通常扫描速度很快,复制速度相比而言要慢一些,如果每次都有大量对象要复制,就会将 STW 时间延长,还有一个情况就是 StringTable ,这个数据结构中存储着 String.intern 方法返回的常连池的引用,YGC 每次都会扫描这个数据结构(HashTable),如果这个数据结构很大,且没有经过 FGC,那么也会拉长 STW 时长,还有一种情况就是操作系统的虚拟内存,当 GC 时正巧操作系统正在交换内存,也会拉长 STW 时长。2. FGC,FGC 我们只能优化频率,无法优化时长,因为这个时长无法控制。如何优化频率呢?触发FGC的原因:1 是 Old 区内存不够,2 是元数据区内存不够,3 是 System.gc(), 4 是 jmap 或者 jcmd,5 是CMS Promotion failed 或者 concurrent mode failure,6 JVM 基于悲观策略认为这次 YGC 后 Old 区无法容纳晋升的对象,因此取消 YGC,提前 FGC优化的策略:1. 通常优化的点是 Old 区内存不够导致 FGC。如果 FGC 后还有大量对象,说明 Old 区过小,应该扩大 Old 区,2. 如果 FGC 后效果很好,说明 Old 区存在了大量短命的对象,优化的点应该是让这些对象在新生代就被 YGC 掉,3. 通常的做法是增大新生代,4. 如果有大而短命的对象,通过参数设置对象的大小,不要让这些对象进入 Old 区,还需要检查晋升年龄是否过小。5. 如果 YGC 后,有大量对象因为无法进入 Survivor 区从而提前晋升,这时应该增大 Survivor 区,但不宜太大。
c. 需要一些工具知道 GC 的状况
1.  jmap, jcmd工具的使用,注意,jmap 和 jcmd dump 文件的时候会触发 FGC ,使用的时候注意场景
2.  jstat,该工具可以查看GC 的详细信息,比如eden ,from,to,old 等区域的内存使用情况
3.  jinfo,该工具可以查看当前 jvm 使用了哪些参数,并且也可以在不停机的情况下修改参数
4.  dump堆内存文件,离线分析
5.  jdk11提供了jhsdb工具

3.3 很重要的一点:线上环境一定要带上 GC 日志。如何配置?

参考1:

# 必备
-XX:+PrintGCDetails # 打印详细的GC日志信息。
-XX:+PrintGCDateStamps #在GC日志中添加时间戳。
-XX:+PrintGCID #打印GC的ID信息。
-XX:+PrintTenuringDistribution #打印对象分布 为了分析 GC 时的晋升情况和晋升导致的高暂停,不看对象年龄分布日志怎么行
-XX:+PrintHeapAtGC # GC 后打印堆数据, 每次发生 GC 时,对比一下 GC 前后的堆内存情况,更直观
-XX:+PrintReferenceGC # 强引用/弱引用/软引用/虚引用/finalize 方法万一有问题,不得打印出来看看?
-XX:+PrintGCApplicationStoppedTime # 打印 STW 时间,暂停时间是 GC 最重要的指标,肯定不能少# 可选
# 打印 safepoint 信息
# 进入STW阶段之前,需要要找到一个合适的 safepoint ,这个指标一样很重要
#(非必选,出现 GC 问题时最好加上此参数调试)
-XX:+PrintSafepointStatistics 
-XX:PrintSafepointStatisticsCount=1# GC日志输出的文件路径,%t带上时间格式
-Xloggc:/path/to/gc-%t.log
# 开启日志文件分割
-XX:+UseGCLogFileRotation 
# 最多分割几个文件,超过之后从头文件开始写
-XX:NumberOfGCLogFiles=14
# 每个文件上限大小,超过就触发分割
-XX:GCLogFileSize=100M

参考2(数据中台的后端服务):

-Xms2g  #堆内存大小
-Xmx2g  #最大堆内存大小
-XX:MetaspaceSize=256m  #元空间
-XX:MaxMetaspaceSize=256m #最大元空间
-XX:MaxDirectMemorySize=1g # 设置New I/O(java.nio)direct-buffer allocations的最大大小
-XX:SurvivorRatio=10 #用于设置新生代中Eden区与Survivor区的空间比例
-XX:+UseConcMarkSweepGC 
-XX:CMSMaxAbortablePrecleanTime=5000 
-XX:+CMSClassUnloadingEnabled 
-XX:CMSInitiatingOccupancyFraction=80 
-XX:+UseCMSInitiatingOccupancyOnly 
-XX:+ExplicitGCInvokesConcurrent 
-Dsun.rmi.dgc.server.gcInterval=2592000000 
-Dsun.rmi.dgc.client.gcInterval=2592000000 
-XX:ParallelGCThreads=8 
-Xloggc:/data/middleLogs/admin-server_gc.log # gc日志配置
-XX:+PrintGCDetails #打印详细的GC日志信息。
-XX:+PrintGCDateStamps #在GC日志中添加时间戳。
-XX:+PrintGCID #打印GC的ID信息。
-XX:+HeapDumpOnOutOfMemoryError # OOM溢出配置
-XX:HeapDumpPath=/admin-server_20230517175814_java.hprof # OOM dump文件存储路径
-Dfile.encoding=UTF-8 
-Dproject.name=admin-server 

4. STW是什么?

  • STW

5. 总结

  • 以上是基本操作,仅供参考
  • 需要学习更多事故排查技术,比如排查 IO,网络,TCP 连接等等。

http://www.ppmy.cn/news/1196322.html

相关文章

女孩子穿这种粉粉嫩嫩~的卫衣也太好看了吧

果然女孩子穿这种粉粉嫩嫩的衣服 真的超级有甜美可爱氛围哎 软糯亲肤的面料,上身很舒服哦 时尚polo领加上半拉链设计 既实用又美观,穿脱很方便

英伟达显卡深度学习训练微调环境安装清单

可以考虑 安装完操作系统后,安装更新及其他基础软件如gcc cmake, 再安装英伟达几件套(这里列出了四个) 如果自带的python版本在3.8或以上,再安装python常用库。 python版本不能太低,看你要跑的代码的需求了…

安装docker可视化工具:Portainer

文章目录 前言一、安装Portainer(docker可视化工具)1.拉镜像2. 启动容器3.查看4.访问 总结 前言 一、安装Portainer(docker可视化工具) 1.拉镜像 docker pull portainer/portainer2. 启动容器 docker run -d -p 8100:8000 -p 9…

2023.11.2事件纪念

然而造化又常常为庸人设计,以时间的流逝,来洗涤旧迹,仅以留下淡红的血色和微漠的悲哀。 回顾这次事件,最深的感触就是什么是团队的力量! 当我们看到希望快要成功的时候,大家洋溢出兴奋开心的表情,一起的欢声笑语;但看…

【Invea Therapeutics】申请7500万美元纳斯达克IPO上市

来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,美国生物制药公司【Invea Therapeutics】近期已向美国证券交易委员会(SEC)提交招股书,申请在纳斯达克IPO上市,股票代码为(INAI) ,Invea …

儿童听力损伤了,家长怎么办?

很多家长对儿童听力损伤问题存在较大误区,认为儿童除了先天性耳聋以外不会有听力问题。家长总认为孩子上课或做事不专心是因为注意力不集中、多动等问题所致,大部分家长没有意识到孩子可能出现了听力损伤问题。 儿童听力损伤主要是指因各种原因导致双耳不…

数据结构构之顺序表

1.线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,也就说是连续的一条直线…

路由器基础(七):NAT原理与配置

一、NAT 配置 华为路由器配置NAT 的方式有很多种,考试中可能考到的基本配置方 式主要有EasyIP和通过NAT地址池的方式。图22-7-1是一个典型的通过EasyIP进行NAT的示意图,其中Router出接口GE0/0/1的IP地址为200.100.1.2/24,接口E0/0/1的IP地址为192.168.0.…