JAVA的CPU过高问题排查

执行模拟程序

本文中,我们会通过测试程序模拟java占用CPU过高,然后通过工具排查出原因。环境:jdk8 centos7

测试程序如下MaxCpuMain.java,模拟了一个高耗CPU线程,5个低耗CPU线程:

import java.util.concurrent.TimeUnit;

public class MaxCpuMain {
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            runMaxCpuCal();
        }).start();

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                runMinCpuCal();
            }).start();
        }

        while (true) {
            Thread.sleep(100);
        }
    }

    public static void runMaxCpuCal() {
        long count = 0;
        while (true) {
            count++;
            double a = Integer.MAX_VALUE + Math.random() * Integer.MAX_VALUE;
            long b = ("sdf" + a).hashCode();
            if (count % (10000 * 10000) == 0) {
                System.out.println("runMaxCpuCal run" + count);
            }
        }
    }

    public static void runMinCpuCal() {
        long count = 0;
        while (true) {
            count++;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count % (30) == 0) {
                System.out.println("runMinCpuCal run" + count);
            }
        }
    }
}

编译运行程序:

[root@centos-7 test]# javac MaxCpuMain.java 
[root@centos-7 test]# java MaxCpuMain
runMinCpuCal run30
runMinCpuCal run30
runMinCpuCal run30
runMinCpuCal run30
runMinCpuCal run30
runMaxCpuCal run100000000

1。TOP定进程PID

通过top(输入大写P按cpu排序)查占用CPU多的pid;查到进程2505。

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND     
 2505 root      20   0 2141720  34020  12112 S 98.3  5.8   2:01.56 java        
    1 root      20   0  128204   4992   3136 S  0.0  0.9   0:01.16 systemd     
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd    
    3 root      20   0       0      0      0 S  0.0  0.0   0:00.04 ksoftirqd/0 
    4 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0 
    5 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H
    6 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kworker/u64+
    7 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0 
    8 root      20   0       0      0      0 S  0.0  0.0   0:00.00 rcu_bh   

2。TOP确认线程Id

通过进程pid查看占用CPU高的线程, top -Hp 2505,查到2515线程

top -Hp 2505
  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND     
 2515 root      20   0 2141720  11976    576 S 89.4  2.1   4:28.63 java        
 2507 root      20   0 2141720  11976    576 R  6.3  2.1   0:14.82 java        
 2505 root      20   0 2141720  11976    576 S  0.0  2.1   0:00.00 java        
 2506 root      20   0 2141720  11976    576 S  0.0  2.1   0:00.16 java        
 2508 root      20   0 2141720  11976    576 S  0.0  2.1   0:00.00 java        
 2509 root      20   0 2141720  11976    576 S  0.0  2.1   0:00.00 java        
 2510 root      20   0 2141720  11976    576 S  0.0  2.1   0:00.00 java        
 2511 root      20   0 2141720  11976    576 S  0.0  2.1   0:00.10 java        

3。jstack确定代码

首先转换出线程id的16进制

 printf '%x' 2515
 9d3

从线程堆栈中追查是哪个线程,执行jstack2505,并在结果搜索9d3线程。

jstack 2505
太长,只列出部分
"Thread-1" #9 prio=5 os_prio=0 tid=0x00007fc1ac0f8800 nid=0x9d4 waiting on condition [0x00007fc1b0d2a000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at MaxCpuMain.runMinCpuCal(MaxCpuMain.java:37)
	at MaxCpuMain.lambda$main$1(MaxCpuMain.java:11)
	at MaxCpuMain$$Lambda$2/303563356.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

"Thread-0" #8 prio=5 os_prio=0 tid=0x00007fc1ac0f6800 nid=0x9d3 runnable [0x00007fc1b0e2b000]
   java.lang.Thread.State: RUNNABLE
	at sun.misc.FloatingDecimal$BinaryToASCIIBuffer.access$100(FloatingDecimal.java:259)
	at sun.misc.FloatingDecimal.getBinaryToASCIIConverter(FloatingDecimal.java:1785)
	at sun.misc.FloatingDecimal.getBinaryToASCIIConverter(FloatingDecimal.java:1738)
	at sun.misc.FloatingDecimal.appendTo(FloatingDecimal.java:89)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:736)
	at java.lang.StringBuilder.append(StringBuilder.java:226)
	at MaxCpuMain.runMaxCpuCal(MaxCpuMain.java:25)
	at MaxCpuMain.lambda$main$0(MaxCpuMain.java:6)
	at MaxCpuMain$$Lambda$1/471910020.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

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

从下面的堆栈中查找9d3,可以得知MaxCpuMain.runMaxCpuCal(MaxCpuMain.java:25)是耗费性能的代码。

 

你可能感兴趣的:(基础知识Java与Linux)