CPU、内存占用率高排查

CPU高占用

排查思路
  1. top 命令查看CPU占用率高的进程
  2. top -H -p ${pid} 命令查看具体是进程的哪个线程占用CPU
  3. printf ‘%x\n’ ${pid} 将线程的pid转为16进制
  4. jstack ${十六进制pid} | grep -A 20 查看线程的基本信息与方法调用栈
模拟排查
[root@VM-24-5-centos www]# top
top - 15:39:55 up 69 days, 13:43,  2 users,  load average: 3.10, 1.75, 0.93
Tasks: 110 total,   1 running, 109 sleeping,   0 stopped,   0 zombie
%Cpu(s): 50.5 us,  0.5 sy,  0.0 ni, 49.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1881840 total,   100232 free,   829564 used,   952044 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   862992 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
27145 root      20   0 2750780  23504  11488 S  99.7  1.2   1:33.06 java
 6493 root      20   0 1033692  51588  16660 S   0.3  2.7 121:18.66 YDService
13842 root      20   0  680292  14520   2464 S   0.3  0.8  10:39.63 barad_agent

PID为27145的java进程占用CPU较多

[root@VM-24-5-centos www]# top -H -p 27145
top - 15:41:10 up 69 days, 13:44,  2 users,  load average: 1.60, 1.58, 0.93
Threads:  13 total,   1 running,  12 sleeping,   0 stopped,   0 zombie
%Cpu(s): 50.3 us,  0.2 sy,  0.0 ni, 49.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1881840 total,   103628 free,   826112 used,   952100 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   866456 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
27157 root      20   0 2750780  23504  11488 R 99.7  1.2   2:47.67 java
27145 root      20   0 2750780  23504  11488 S  0.0  1.2   0:00.00 java
27146 root      20   0 2750780  23504  11488 S  0.0  1.2   0:00.10 java

PID为27145的java进程的PID为27157的子线程占用CPU较多

[root@VM-24-5-centos www]# jstack 27145 | grep 0x6a15 -A 20
"Business Thread" #8 prio=5 os_prio=0 tid=0x00007f545c102000 nid=0x6a15 runnable [0x00007f544c6f5000]
   java.lang.Thread.State: RUNNABLE
	at CPUOccupancyRateTest.lambda$businessThread$0(CPUOccupancyRateTest.java:10)
	at CPUOccupancyRateTest$$Lambda$1/834600351.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f545c0b9000 nid=0x6a13 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f545c0b6000 nid=0x6a12 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f545c0b3000 nid=0x6a11 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f545c0b1800 nid=0x6a10 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f545c07e800 nid=0x6a0f in Object.wait() [0x00007f544ccfb000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
[root@VM-24-5-centos www]#

将线程的PID转为16进制后,通过jstack该线程的信息与方法调用栈,该线程的名称为: Business Thread,可定位到执行代码:CPUOccupancyRateTest.java:10。看下具体java代码:

public class CPUOccupancyRateTest {

    public static void main(String[] args) {
        businessThread();
    }

    static void businessThread() {
        Thread thread = new Thread(() -> {
            while (true) {  // line 10
                // Do nothing
            }
        });
        thread.setName("Business Thread");
        thread.start();
    }
}

内存高占用(使用MAT分析)

排查思路

若仍未发生OOM:

  1. top 命令查看Memeory占用率高的java进程
  2. jmap dump java进程的内存快照文件
  3. 通过可视化分析工具导入快照文件进行排查
    3.1. 占用内存过多的对象是哪些
    3.2. 这些对象被谁引用
    3.3. 定位到具体代码

注:若堆内存很大时,直接在线上服务器执行 jmap dump 内存快照文件,会导致长时间STW来导出很大的快照文件,引发服务程序不可用。

若发生了OOM,通过配置的JVM启动参数:

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=${path}

找到快照文件,导入到可视化分析工具中分析。

OOM模拟排查

JVM启动参数

-Xmx10m -Xms10m 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/Users/congqingquan/Desktop

测试代码

public class OOMTest {

    public static void main(String[] args) {
        oomTest();
    }

    static void oomTest() {
        Thread thread = new Thread(() -> {
            List<Person> list = new ArrayList<>();
            while (true) {
                list.add(new Person());
            }
        });

        thread.setName("OOM Test Thread");
        thread.start();
    }

    static class Person {}
}
使用MAT引入快照文件进行分析

MAT下载地址,红、黄框为常用的分析功能

在这里插入图片描述

Histogram

类的实例对象的柱状统计分析图

在这里插入图片描述

默认以Byte为单位展示数据,若需要更改显示单位可以在:
Preferences -> Memory Analyzer -> Bytes Display 中选择,一般使用Smart选项。

字段解释:

  1. Objects:实例对象的数量
  2. Shallow Heap:实例对象占用的内存大小(仅单纯的将每个实例的大小相加汇总)
  3. Retained Heap:实例对象若都可以被回收,那么可以被GC释放的内存大小(不仅需要考虑每个实例本身的大小,也会计算实例成员属性指向的实例的大小)
Dominator_tree

在这里插入图片描述

Dominator Tree(支配树)视图,列出了每个对象实例的引用关系的树状图,包含了占用内存的大小和百分比。

字段解释:

  1. Shallow Heap:实例对象占用的内存大小(仅单纯的将每个实例的大小相加汇总)
  2. Retained Heap:实例对象若都可以被回收,那么可以被GC释放的内存大小(不仅需要考虑每个实例本身的大小,也会计算实例成员属性指向的实例的大小)
  3. Percentage:占用堆内存的百分比
Thread_overview

在这里插入图片描述

线程概述:程序中所有的线程的信息,如:方法调用栈,方法的栈帧,每个线程、方法中创建的对象以及占用堆内存大小。

字段解释:

  1. Name:线程名称
  2. Shallow Heap:实例对象占用的内存大小(仅单纯的将每个实例的大小相加汇总)
  3. Retained Heap:实例对象若都可以被回收,那么可以被GC释放的内存大小(不仅需要考虑每个实例本身的大小,也会计算实例成员属性指向的实例的大小)
  4. Context Class Loader:上下文类加载器
  5. Is Daemon:是否为守护线程
回顾排查思路中的第三步,使用排查工具分析:
  1. 占用内存过多的对象是哪些?Histogram,可以直观的看到统计数据
  2. 这些对象被谁引用?Dominator_tree,从根对象角度,根据Retained Heap排序,查看哪个GC Root对象的引用关系树中存在的对象占用内存过大
  3. 定位到具体代码?Thread_overview,从线程角度,根据Retained Heap排序,查看哪个线程生成的对象占用内存过多,分布在线程的哪些方法中。

由于案例比较简单,通过MAT常用功能的讲解,已经可以在解释截图中看到问题根源了:

  1. Histogram 视图说明了占用内存过多的对象:Person。
  2. Thread_overview 视图说明了这些对象主要集中在OOM Test Thread线程中。通过线程的方法调用栈,可以看到问题出在oomTest方法上,因为方法内的某个lambda表达式中的一个局部变量ArrayList对象存储了大量的数据。截图中我并没有展开,里面存储的正是大量的Person实例。
Leak Suspects

在这里插入图片描述

泄漏疑点:MAT会根据快照文件帮助你分析,并列出分析后的可疑点。点击Detail有更具体的详细说明,非常好用~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
kswapd1 是 Linux 系统中的一个进程,它负责处理和管理内存中的页面交换(swapping)工作。当内存不足时,kswapd1 会将部分不常用的页面(页面是内存中分配的最小单元)调出到交换分区(swap partition)中,以释放更多的可用内存。 当 kswapd1 的 CPU 占用率时,主要有以下可能原因: 1. 内存压力:当系统内存不足,kswapd1 需要频繁进行页面交换操作,以释放可用内存。这会导致 kswapd1 占用CPU 资源。可以通过查看系统内存使用情况和交换分区使用情况来确认是否存在内存压力问题。 2. 内存泄漏:系统中某个进程可能存在内存泄漏的情况,导致内存不断增加,使得 kswapd1 不断进行页面交换。可以使用系统工具来监测进程的内存使用情况,找出是否存在内存泄漏的进程。 3. 磁盘 I/O 问题:当系统的交换分区位于较慢的磁盘上,或者磁盘本身存在故障,会导致 kswapd1 进程占用CPU 资源。可以通过检查磁盘状态以及磁盘 I/O 操作来确定是否存在此问题。 为解决 kswapd1 CPU 占用率问题,可以尝试以下解决方案: 1. 增加物理内存:如果系统内存不足,可以考虑增加物理内存,以减少对页面交换的需求。 2. 优化内存使用:检查系统中的进程,找出可能存在内存泄漏的进程,并进行相应的处理或调优。 3. 优化磁盘性能:如果磁盘 I/O 是导致 kswapd1 CPU 占用率的原因,可以优化磁盘性能,例如更换较慢的磁盘,修复磁盘故障等。 总体而言,解决 kswapd1 CPU 占用率问题需要综合考虑内存状况、进程的内存使用情况以及磁盘性能等因素,找出问题的根本原因,并采取相应的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值