前言

本文介绍服务器内运行的 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. 被收费绘图工具 PUA 了怎么办?来看看这个老实工具吧

    本文非常适合 Electron 入门选手,墙裂推荐! 本文作者:HelloGitHub-蔡文心 大家好!这里是 HelloGitHub 推出的<讲解开源项目>系列,今天给大家带来的一款基于 ...

  2. java调用http接口的几种方式总结

    本文参考: https://blog.csdn.net/fightingXia/article/details/71775516 https://www.cnblogs.com/jeffen/p/69 ...

  3. Java 并发机制底层实现 —— volatile 原理、synchronize 锁优化机制

    本书部分摘自<Java 并发编程的艺术> 概述 相信大家都很熟悉如何使用 Java 编写处理并发的代码,也知道 Java 代码在编译后变成 Class 字节码,字节码被类加载器加载到 JV ...

  4. C++ 指针 new delete int*与string

    一 指针 string和int 都可以认为是四个字节sizeof(string)==4, string是个类,它的空间在堆动态分配 二.delete 只是释放空间 三.new 数组 int size= ...

  5. codeforces 8B

    B. Obsession with Robots time limit per test 2 seconds memory limit per test 64 megabytes input stan ...

  6. ubuntu+将主机编译的库链接到虚拟环境Python中

    这里且以opencv为例: cd ~/.virtualenvs/YOUR_ENV/lib/python3.5/site-packages/ ln -s /usr/local/lib/python3.5 ...

  7. 解决.dll类等文件丢失或出错

    简单暴力: 去官网下载WIN10 SDK 并安装, 将本机的DLL类文件重新刷新一遍. https://developer.microsoft.com/en-US/windows/downloads/ ...

  8. 电信悦 me 智能网关

    电信悦 me 智能网关 悦 me 智能网关 Q1:什么是电信悦 me 智能网关? 悦me网关是智慧家庭的核心终端,作为"光猫+智能路由器"的集合体, 采用了全新的硬件.外观及智能操 ...

  9. ES2020 All in One

    ES2020 All in One ES2020 new features / ES11 ES2020 中的10个新功能 1. BigInt BigInt是JavaScript中最令人期待的功能之一, ...

  10. VSCode & Node.js & debugger & inspector

    VSCode & Node.js & debugger & inspector F5 ws 元信息 (UUID) ws://127.0.0.1:46912/efa91bda-1 ...