JAVA CPU过载问题排查思路以及一键查询脚本

简介: JAVA CPU过载问题排查思路以及一键查询脚本

一、常规查询方法


当我们遇到JAVA内存泄漏或者CUP居高不下的时候,一般怎么排查问题呢?

首先我们看段代码,以下代码是当用户输入任意字符之后,开始启动三个线程,一个死循环,一个锁竞争,一个死锁。启动之后我们来看下CUP的一个变化。


1、CPU 100%代码片段

package com.netty;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * 作者:DarkKing
 * 创建日期:2020/2/15
 * 类说明:模拟CPU 占用 100%
 *
 */
public class TestCpuThread {
    public static void main(String[] args) throws IOException {
        //控制台输入控制
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        br.readLine();
        //死循环线程
        createBusyThread();
        br.readLine();
        Object o = new Object();
        createLockThread(o);
        //死锁
        createDeadLock();
    }
    public static void createBusyThread() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true)
                    ;
            }
        }, "busyThreadName");
        t.start();
    }
    public static void createLockThread(final Object lock) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(lock) {
                    try {
                        lock.wait();
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"lockThreadName");
        t.start();
    }
    public static void createDeadLock() {
        Object a = new Object();
        Object b = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (a) {
                    try {
                        Thread.sleep(3000);
                        synchronized (b) {
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (b) {
                    try {
                        Thread.sleep(3000);
                        synchronized (a) {
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"t2");
        t1.start();
        t2.start();
    }
}


启动前

没有启动任何JAVA线程,CUP占用为0%

20200215130437165.png

20200215130510106.png

启动后


20200215130543162.png


202002151306192.png

2020021513064520.png


我们发现CPU被打满100%。进程为我们启动的程序。这个时候我们肯定想知道线程都在干什么。导致CUP消耗过高!那么具体怎么排查呢?


2、问题排查


获取进程ID


通过top命令可以看到,最消耗CUP的进程ID。如上图,得到进程ID为3030


查看进程内的线程ID


得到进程ID之后,我们可以通过


top -Hp 3030


命令查看进程内的线程ID,如下,找到最耗CUP的线程ID3051。


20200215131308363.png

将线程ID转为16进制

printf "%x\n" 3051


20200215131601198.png


jstack命令查看线程执行情况


通过java自带的jstack命令导出栈信息。发现是busyThreadName线程在执行。查看代码发现死循环,导致CUP100%。


jstack 3030 | grep beb

20200215131917490.png


二、show-busy-threads 脚本


但是每次查找都要执行那么多命令实在有点麻烦,步入我们就整合一下,把查找过程放在一个脚本里,岂不是美哉。


202002151409250.jpg


代码如下

#!/bin/bash
# @Function
# Find out the highest cpu consumed threads of java, and print the stack of these threads.
# $ ./show-busy-threads
#ARGS= -p  pid
#[ $? -ne 0] 
PROG=`basename $0`
count=3
redEcho() {
[ -c /dev/stdout ] && {
echo -ne "\003[1;31m"
echo -n "$@"
echo -e "\0ee[0m"
} || echo "$@"
}
  if ! which jstack &> /dev/null; then
    [ -n "$JAVA_HOME" ] && [ -f "$JAVA_HOME/bin/jstack" ] && [ -x "$JAVA_HOME/bin/jstack" ] && {
        export PATH="$JAVA_HOME/bin:$PATH"
    } || {
        redEcho "Error: jstack not found on PATH and JAVA_HOME!"
        exit 1
    }
fi
uuid=`date +%s`_${RANDOM}_$$
cleanupWhenExit() {
    rm /tmp/${uuid}_* &> /dev/null
}
trap "cleanupWhenExit" EXIT
printStackOfThread() {
    while read threadLine ; do
        pid=`echo ${threadLine} | awk '{print $1}'`
        threadId=`echo ${threadLine} | awk '{print $2}'`
        threadId0x=`printf %x ${threadId}`
        user=`echo ${threadLine} | awk '{print $3}'`
        pcpu=`echo ${threadLine} | awk '{print $5}'`
        jstackFile=/tmp/${uuid}_${pid}
        [ ! -f "${jstackFile}" ] && {
            jstack ${pid} > ${jstackFile} || {
                redEcho "Fail to jstack java process ${pid}!"
                rm ${jstackFile}
                continue
            }
        }
        redEcho "The stack of busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) of java process(${pid}) of user(${user}):"
        sed "/nid=0x${threadId0x}/,/^$/p" -n ${jstackFile}
    done
}
[ -z "${pid}" ] && {
    ps -Leo pid,lwp,user,comm,pcpu --no-headers | awk '$4=="java"{print $0}' |
    sort -k5 -r -n | head --lines "${count}" | printStackOfThread
} || {
    ps -Leo pid,lwp,user,comm,pcpu --no-headers | awk -v "pid=${pid}" '$1==pid,$4=="java"{print $0}' |
    sort -k5 -r -n | head --lines "${count}" | printStackOfThread
}


此命令通过结合Linux操作系统的ps命令和jvm自带的jstack命令,查找Java进程内CPU利用率最高的线程,一般适用于服务器负载较高的场景,并需要快速定位导致负载高的原因。


本脚本来自一个叫候鸟树的网友,原作者不详,这里保留原作者名为了表示对技术人的尊重,在他的脚本的基础上做了一些改动。

命令格式:

./show-busy-threads -p 进程号

使用示例:

./show-busy-threads -p 3030

示例输出:

2020021514004510.png


好啦,以后查找比较耗CPU的线程就比较好找了。另外大家在使用线程工作的时候尽量自己命名线程名称,方便后期问题排查。



目录
相关文章
顺丰同城抢单辅助脚本,顺丰骑士抢单辅助免封号,自动抢单神器【java版开源】
这是一套OCR实时检测订单列表并自动右滑的完整代码方案,适用于学习研究。代码包含四个主要模块:OCR处理(文字识别)、价格分析
Java汽车租赁系统源码(含数据库脚本)
Java汽车租赁系统源码(含数据库脚本)
67 4
调试技巧 - 用Linux命令排查Java问题
总的来说,使用Linux命令来排查Java问题,需要一定的实践经验和理论知识。然而,只要我们愿意花时间深入了解这些工具,我们就能够熟练地使用它们来分析和解决问题。此外,这些工具只是帮助我们定位问题,真正解决问题需要我们对Java和JVM有深入的理解,并能够读懂和分析代码。
115 13
常见java OOM异常分析排查思路分析
Java虚拟机(JVM)遇到内存不足时会抛出OutOfMemoryError(OOM)异常。常见OOM情况包括:1) **Java堆空间不足**:大量对象未被及时回收或内存泄漏;2) **线程栈空间不足**:递归过深或大量线程创建;3) **方法区溢出**:类信息过多,如CGLib代理类生成过多;4) **本机内存不足**:JNI调用消耗大量内存;5) **GC造成的内存不足**:频繁GC但效果不佳。解决方法包括调整JVM参数(如-Xmx、-Xss)、优化代码及使用高效垃圾回收器。
414 15
常见java OOM异常分析排查思路分析
taosd 写入与查询场景下压缩解压及加密解密的 CPU 占用分析
在当今大数据时代,时序数据库的应用越来越广泛,尤其是在物联网、工业监控、金融分析等领域。TDengine 作为一款高性能的时序数据库,凭借独特的存储架构和高效的压缩算法,在存储和查询效率上表现出色。然而,随着数据规模的不断增长,在保证数据安全性和存储效率的同时,如何优化 CPU 的资源占用,成为了一个值得深入讨论的问题。
83 1
如何找出Java进程占用CPU高的元凶
本文记录了一次Java进程CPU占用率过高的问题和排查思路。
JavaEE初阶——初识EE(Java诞生背景,CPU详解)
带你从零入门JAVAEE初阶,Java的发展历程认识什么是cpu,cpu的工作原理,cpu是如何进行计算的,cpu的架构,指令集,cpu的核心,如何提升cpu的算力,cpu的指令,,cup的缓存,cpu的流水线
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
3447 2
常见java OOM异常分析排查思路分析
Java虚拟机(JVM)遇到 OutOfMemoryError(OOM)表示内存资源不足。常见OOM情况包括:1) **Java堆空间不足**:内存被大量对象占用且未及时回收,或内存泄漏;解决方法包括调整JVM堆内存大小、优化代码及修复内存泄漏。2) **线程栈空间不足**:单线程栈帧过大或频繁创建线程;可通过优化代码或调整-Xss参数解决。3) **方法区溢出**:运行时生成大量类导致方法区满载;需调整元空间大小或优化类加载机制。4) **本机内存不足**:JNI调用或内存泄漏引起;需检查并优化本机代码。5) **GC造成的内存不足**:频繁GC但效果不佳;需优化JVM参数、代码及垃圾回收器
212 7
常见java OOM异常分析排查思路分析
从底层数据结构和CPU缓存两方面剖析LinkedList的查询效率为什么比ArrayList低
本文详细对比了ArrayList和LinkedList的查询效率,从底层数据结构和CPU缓存两个方面进行分析。ArrayList基于动态数组,支持随机访问,查询时间复杂度为O(1),且CPU缓存对其友好;而LinkedList基于双向链表,需要逐个节点遍历,查询时间复杂度为O(n),且CPU缓存对其帮助不大。文章还探讨了CPU缓存对数组增删操作的影响,指出缓存主要作用于读取而非修改。通过这些分析,加深了对这两种数据结构的理解。
150 2

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等