JVM线上问题排查
前言
本文介绍服务器内运行的 Java 应用产生的 OOM 问题 和 CPU 100% 的问题定位
1. 内存 OOM 问题定位
某Java服务(比如进程id pid 为 3320)出现OOM,常见的原因为:
- 内存分配的确实小了,而正常业务使用了大量的内存
- 某个对象被频繁申请,却没有释放,内存不断泄露,导致内存耗尽
- 某个资源被频繁申请,系统资源耗尽。例如不断创建线程,不断发起网络请求。
资源不够(也是"给的资源耗尽"),资源申请过多导致资源耗尽,资源申请过多不释放导致资源耗尽。
以下为使用工具排查方法:
1.1 jmap 确认内存是否分配过小
命令:jmap -heap 3320
可查看新生代,老年代堆内部内存的分配大小以及使用情况。看是否是因为分配的过小

1.2 找到最耗内存的对象
jmap -histo:live 3320 | more

[C is a char[]
[S is a short[]
[I is a int[]
[B is a byte[]
[[I is a int[][]
会以表格的形式显示存活对象的信息,并按内存大小排序。(num:排名,instances:实例数,bytes:所占内存大小,class name: 类名)上面的输出中[C对象占用Heap这么多,往往跟String有关,String其内部使用final char[]数组来保存数据的。
对于实例数较多,占用内存大小较多的实例/类,相关的代码就要针对性review了。上图占用最多的是[C 占用30M。
如果发现某类对象占用内存很大(例如几个G),很可能是类对象创建太多,且一直未释放。例如:
- 申请完资源后,未调用close()或dispose()释放资源
- 消费者消费速度慢(或停止消费了),而生产者不断往队列中投递任务,导致队列中任务累积过多
线上执行该命令会强制执行一次fgc。另外还可以dump内存进行分析。
1.3 确认是否是资源耗尽
工具:
- pstree
- netstat
查看进程创建的线程数,以及网络连接数,如果资源耗尽,也可能出现OOM。
这里介绍另一种方法,通过
- /proc/${PID}/fd
- /proc/${PID}/task
可以分别查看句柄详情和线程数。


如上图,sshd共占用了四个句柄
- 0 -> 标准输入
- 1 -> 标准输出
- 10 -> 标准错误输出
- 100 -> socket(容易想到是监听端口)
文件描述符fd。linux中, 每一个进程在内核中,都对应有一个“打开文件”数组,存放指向文件对象的指针,而 fd 是这个数组的下标。 我们对文件进行操作时,系统调用,将fd传入内核,内核通过fd找到文件,对文件进行操作。
fd作为数组下标,fd的类型为int, < 0 为非法值, >=0 为合法值。在linux中,一个进程默认可以打开的文件数为1024个,fd的范围为0~1023。可以通过设置,改变最大值。在linux中,值为0、1、2的fd,分别代表标准输入、标准输出、标准错误输出。
- ll /proc/${PID}/fd | wc -l
- ll /proc/${PID}/task | wc -l (效果等同pstree -p | wc -l)
就能知道进程打开的句柄数和线程数。

2. CPU 100% 问题定位
线上服务器中如果多实例部署,如何定位是哪个服务进程导致CPU过载,哪个线程导致CPU过载,那段代码导致CPU过载?
大致步骤如下:
- 找到最耗CPU 的进程
- 找到最耗CPU 的线程
- 查看堆栈,定位线程在干嘛,定位对应代码
2.1 找到最耗 CPU 的进程
使用 top 命令
- 执行 top -c 查看进程运行信息列表
- 输入P(大写) 进程按照CPU 使用率排序
好像top后就是按cpu使用率来排序的。

如上图 最耗CPU的进程PID是7199
2.2 找到最耗 CPU 的线程
使用 top命令
- top -Hp 7199 显示一个进程的线程运行信息
- 输入大写P ,线程按照CPU使用率排序

如上图 进程 7199 中 最耗CPU的线程PID为7248
2.3 查看堆栈 定位对应代码
- 将线程PID 转化为16进制
使用 printf "%x\n" 7248
返回 1c50
- 参看堆栈,找到线程在干嘛
使用 jstack 7199 | grep '0x1c50' -C5 --color
- 打印进程堆栈
- 通过线程id 过滤得到线程堆栈

如上图 耗CPU 最高的线程对应的线程名称 "Thread-7" 以及相应的代码 A.java
- 根据堆栈信息,找到相应的代码
3. 其他方法
上面的方法比较原始,并且比较繁琐,一般使用现有的轮子
arthas 快速高效
- 在使用 Arthas 之前,当遇到 Java 线上问题时,如 CPU 飙升、负载突高、内存溢出等问题,你需要查命令,查网络,然后 jps、jstack、jmap、jhat、jstat、hprof 等一通操作。最终焦头烂额,还不一定能查出问题所在。而现在,大多数的常见问题你都可以使用 Arthas 轻松定位,迅速解决,及时止损,准时下班。
- Arthas 是 Alibaba 在 2018 年 9 月开源的 Java 诊断工具。
show busy java thread 脚本
- 将上面的步骤进行脚本封装,执行脚本直接得出结果,目前仅在linux上使用
- link
jmc
- jdk bin目录下工具,可对应用进行监控
References
JVM线上问题排查的更多相关文章
- JVM 线上故障排查基本操作--CPU飙高
JVM 线上故障排查基本操作 CPU 飚高 线上 CPU 飚高问题大家应该都遇到过,那么如何定位问题呢? 思路:首先找到 CPU 飚高的那个 Java 进程,因为你的服务器会有多个 JVM 进程.然后 ...
- JVM 线上故障排查
JVM 线上故障排查 Linux 1.1 CPU 1.2 内存 1.3 存储 1.4 网络 一.CPU 飚高 寻找原因 二.内存问题排查 三.一般排查问题的方法 四.应用场景举例 4.1 怎么查看某个 ...
- JVM 线上故障排查基本操作
# 前言 对于后端程序员,特别是 Java 程序员来讲,排查线上问题是不可避免的.各种 CPU 飚高,内存溢出,频繁 GC 等等,这些都是令人头疼的问题.楼主同样也遇到过这些问题,那么,遇到这些问题该 ...
- JVM 线上故障排查基本操作--内容问题排查
内存问题排查 说完了 CPU 的问题排查,再说说内存的排查,通常,内存的问题就是 GC 的问题,因为 Java 的内存由 GC 管理.有2种情况,一种是内存溢出了,一种是内存没有溢出,但 GC 不健康 ...
- JVM 线上故障排查基本操作 (转)
前言 对于后端程序员,特别是 Java 程序员来讲,排查线上问题是不可避免的.各种 CPU 飚高,内存溢出,频繁 GC 等等,这些都是令人头疼的问题.楼主同样也遇到过这些问题,那么,遇到这些问题该如何 ...
- Java线上问题排查思路及Linux常用问题分析命令学习
前言 之前线上有过一两次OOM的问题,但是每次定位问题都有点手足无措的感觉,刚好利用星期天,以测试环境为模版来学习一下Linux常用的几个排查问题的命令. 也可以帮助自己在以后的工作中快速的排查线上问 ...
- 线上问题排查神器 Arthas
线上问题排查神器 Arthas 之前介绍过 BTrace,线上问题排查神器 BTrace 的使用,也说它是线上问题排查神器.都是神器,但今天这个也很厉害,是不是更厉害不好说,但是使用起来非常简单.如果 ...
- java:线上问题排查常用手段(转)
出处:java:线上问题排查常用手段 一.jmap找出占用内存较大的实例 先给个示例代码: import java.util.ArrayList; import java.util.List; imp ...
- Java线上问题排查神器Arthas实战分析
概述 背景 是不是在实际开发工作当中经常碰到自己写的代码在开发.测试环境行云流水稳得一笔,可一到线上就经常不是缺这个就是少那个反正就是一顿报错抽风似的,线上调试代码又很麻烦,让人头疼得抓狂:而且deb ...
随机推荐
- C#异步和多线程以及Thread、ThreadPool、Task区别和使用方法
本文的目的是为了让大家了解什么是异步?什么是多线程?如何实现多线程?对于当前C#当中三种实现多线程的方法如何实现和使用?什么情景下选用哪一技术更好? 第一部分主要介绍在C#中异步(async/awai ...
- Yocto项目介绍及入门 -- 嵌入师工程师必备利器
目录 写在前面 1. Yocto项目是什么 2. Yocto项目有什么用 3. 如何快速上手Yocto项目 4. 带你通过Yocto项目编译一个自定义镜像文件 写在前面 博主目前从事BMC工作,由于公 ...
- kubernetes实战-交付dubbo服务到k8s集群(四)使用blue ocean流水线构建dubbo-demo-service
使用jenkins创建一个新的项目:dubbo-demo,选择流水线构建 勾选保存构建历史和指定项目为参数化构建项目: 添加构建参数:以下配置项,是王导根据多年生产经验总结出来的甩锅大法: 除了bas ...
- kubernetes进阶(六)k8s平滑升级
当我们遇到K8S有漏洞的时候,或者为了满足需求,有时候可能会需要升级或者降级版本, 为了减少对业务的影响,尽量选择在业务低谷的时候来升级: 首先准备好文件:我这里选择的是内网文件服务器上下载的,请自行 ...
- MSE,RMSE
MSE: Mean Squared Error 均方误差是指参数估计值与参数真值之差平方的期望值; MSE可以评价数据的变化程度,MSE的值越小,说明预测模型描述实验数据具有更好的精确度. RMSE ...
- C++中main函数的返回值一定要是int
因为大学上课时候,经常是在主函数中做处理,直接用cout语句输出到显示设备,所以一直在用void main(). 直到后面具体编程的时候,才发现void main()这种用法是按 C89(C语言的早期 ...
- mysql(四)------Mysql中的锁
1. 2 MySQL InnoDB 锁的基本类型 https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html 官网把锁分成了 8 类.所以我 ...
- CNN可视化技术总结(四)--可视化工具与项目
CNN可视化技术总结(一)-特征图可视化 CNN可视化技术总结(二)--卷积核可视化 CNN可视化技术总结(三)--类可视化 导言: 前面介绍了可视化的三种方法--特征图可视化,卷积核可视化,类可视化 ...
- 二分类问题中混淆矩阵、PR以及AP评估指标
仿照上篇博文对于混淆矩阵.ROC和AUC指标的探讨,本文简要讨论机器学习二分类问题中的混淆矩阵.PR以及AP评估指标:实际上,(ROC,AUC)与(PR,AP)指标对具有某种相似性. 按照循序渐进的原 ...
- 使用 Promise 实现请求自动重试
使用 Promise 实现请求自动重试 "use strict"; /** * * @author xgqfrms * @license MIT * @copyright xgqf ...