前言

本文介绍服务器内运行的 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过载?

大致步骤如下:

  1. 找到最耗CPU 的进程
  2. 找到最耗CPU 的线程
  3. 查看堆栈,定位线程在干嘛,定位对应代码

2.1 找到最耗 CPU 的进程

使用 top 命令

  1. 执行 top -c 查看进程运行信息列表
  2. 输入P(大写) 进程按照CPU 使用率排序

好像top后就是按cpu使用率来排序的。

如上图 最耗CPU的进程PID是7199

2.2 找到最耗 CPU 的线程

使用 top命令

  1. top -Hp 7199 显示一个进程的线程运行信息
  2. 输入大写P ,线程按照CPU使用率排序

如上图 进程 7199 中 最耗CPU的线程PID为7248

2.3 查看堆栈 定位对应代码

  1. 将线程PID 转化为16进制

使用 printf "%x\n" 7248

返回 1c50

  1. 参看堆栈,找到线程在干嘛

使用 jstack 7199 | grep '0x1c50' -C5 --color

  • 打印进程堆栈
  • 通过线程id 过滤得到线程堆栈



如上图 耗CPU 最高的线程对应的线程名称 "Thread-7" 以及相应的代码 A.java

  1. 根据堆栈信息,找到相应的代码

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线上问题排查的更多相关文章

  1. JVM 线上故障排查基本操作--CPU飙高

    JVM 线上故障排查基本操作 CPU 飚高 线上 CPU 飚高问题大家应该都遇到过,那么如何定位问题呢? 思路:首先找到 CPU 飚高的那个 Java 进程,因为你的服务器会有多个 JVM 进程.然后 ...

  2. JVM 线上故障排查

    JVM 线上故障排查 Linux 1.1 CPU 1.2 内存 1.3 存储 1.4 网络 一.CPU 飚高 寻找原因 二.内存问题排查 三.一般排查问题的方法 四.应用场景举例 4.1 怎么查看某个 ...

  3. JVM 线上故障排查基本操作

    # 前言 对于后端程序员,特别是 Java 程序员来讲,排查线上问题是不可避免的.各种 CPU 飚高,内存溢出,频繁 GC 等等,这些都是令人头疼的问题.楼主同样也遇到过这些问题,那么,遇到这些问题该 ...

  4. JVM 线上故障排查基本操作--内容问题排查

    内存问题排查 说完了 CPU 的问题排查,再说说内存的排查,通常,内存的问题就是 GC 的问题,因为 Java 的内存由 GC 管理.有2种情况,一种是内存溢出了,一种是内存没有溢出,但 GC 不健康 ...

  5. JVM 线上故障排查基本操作 (转)

    前言 对于后端程序员,特别是 Java 程序员来讲,排查线上问题是不可避免的.各种 CPU 飚高,内存溢出,频繁 GC 等等,这些都是令人头疼的问题.楼主同样也遇到过这些问题,那么,遇到这些问题该如何 ...

  6. Java线上问题排查思路及Linux常用问题分析命令学习

    前言 之前线上有过一两次OOM的问题,但是每次定位问题都有点手足无措的感觉,刚好利用星期天,以测试环境为模版来学习一下Linux常用的几个排查问题的命令. 也可以帮助自己在以后的工作中快速的排查线上问 ...

  7. 线上问题排查神器 Arthas

    线上问题排查神器 Arthas 之前介绍过 BTrace,线上问题排查神器 BTrace 的使用,也说它是线上问题排查神器.都是神器,但今天这个也很厉害,是不是更厉害不好说,但是使用起来非常简单.如果 ...

  8. java:线上问题排查常用手段(转)

    出处:java:线上问题排查常用手段 一.jmap找出占用内存较大的实例 先给个示例代码: import java.util.ArrayList; import java.util.List; imp ...

  9. Java线上问题排查神器Arthas实战分析

    概述 背景 是不是在实际开发工作当中经常碰到自己写的代码在开发.测试环境行云流水稳得一笔,可一到线上就经常不是缺这个就是少那个反正就是一顿报错抽风似的,线上调试代码又很麻烦,让人头疼得抓狂:而且deb ...

随机推荐

  1. Spring:解决因@Async引起的循环依赖报错

    最近项目中使用@Async注解在方法上引起了循环依赖报错: org.springframework.beans.factory.BeanCurrentlyInCreationException: Er ...

  2. Redis之哨兵机制(sentinel)——配置详解及原理介绍

    说到Redis不得不提哨兵模式,那么究竟哨兵是什么意思?为什么要使用哨兵呢? 接下来一一为您讲解: 1.为什么要用到哨兵 哨兵(Sentinel)主要是为了解决在主从(master-slave)复制架 ...

  3. Postman查看上传文件过程时出现400 - Required MultipartFile parameter 'files' is not present错误

    我在利用postman查看上传图片文件时,出现了如下图的错误,看到之后很懵逼. 图1 上网搜了一下,归结下来就是参数不一致导致的.不过还有一些是由于没加注解,如下图示: 图2 关于参数不一致问题,主要 ...

  4. Leetcode(94)-二叉树的中序遍历

    给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 思路:和上篇的前序遍历一样,同样有递归和非递归的做法 (1)递归 vecto ...

  5. POJ3233 构造子矩阵+矩阵快速幂

    题意:给你矩阵A,求S=A+A^1+A^2+...+A^n sol:直接把每一项解出来显然是不行的,也没必要. 我们可以YY一个矩阵: 其中1表示单位矩阵 然后容易得到: 可以看出这个分块矩阵的左下角 ...

  6. nmap进阶使用[脚本篇]

        nmap 进阶使用 [ 脚本篇 ] 2017-05-18 NMAP 0x01 前言 因为今天的重点并非nmap本身使用,这次主要还是想给大家介绍一些在实战中相对比较实用的nmap脚本,所以关于 ...

  7. javascript questions & code review

    javascript questions & code review refs https://github.com/learning-js-by-reading-source-codes/j ...

  8. web 安全 & web 攻防: XSS(跨站脚本攻击)和 CSRF(跨站请求伪造)

    web 安全 & web 攻防: XSS(跨站脚本攻击)和 CSRF(跨站请求伪造) XSS(跨站脚本攻击)和CSRF(跨站请求伪造) Cross-site Scripting (XSS) h ...

  9. React Suspense All In One

    React Suspense All In One 挂起让组件在渲染之前"等待"某些东西. 如今,Suspense仅支持一种用例:使用React.lazy动态加载组件. 将来,它将 ...

  10. full page screen capture in js

    full page screen capture in js html2canvas https://html2canvas.hertzen.com/ https://github.com/nikla ...