Linux下如何定位最耗CPU的JAVA代码

简介: Linux下如何定位最耗CPU的JAVA代码

引言

程序运行卡的时候,我们经常需要定位到底程序在执行什么代码最消耗CPU,这里有个我经常用的小技巧,分享一下。

过程如下:

首先,Linux下面top命令可以直接找出最消耗CPU的进程  
top

可以看到如下显示,我们看到前面有三个都是100% CPU占用的

top - 19:53:23 up 118 days,  6:09,  4 users,  load average: 3.00, 2.68, 1.68
Tasks: 446 total,   1 running, 438 sleeping,   7 stopped,   0 zombie
Cpu(s):  8.6%us,  4.2%sy,  0.0%ni, 87.2%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  132103700k total, 76585104k used, 55518596k free,   424052k buffers
Swap: 16383996k total,        0k used, 16383996k free, 36290728k cached

   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                             
156888 hdfs      20   0 34.9g 544m  11m S 100.8  0.4   9:44.08 java                                                                                                                                                
156928 hdfs      20   0 34.9g 545m  11m S 100.8  0.4   9:42.84 java                                                                                                                                                
156769 hdfs      20   0 34.9g 544m  11m S 100.2  0.4   9:53.26 java                                                                                                                                                
153980 hdfs      20   0 64.0g  24g  55m S  1.7 19.6   5879:56 presto-server                                                                                                                                        
   105 root      20   0     0    0    0 S  0.3  0.0  45:26.08 events/6                                                                                                                                             
   106 root      20   0     0    0    0 S  0.3  0.0   4:41.29 events/7   代码片

接下来,我们一个个分析,先找第一个最消耗CPU的,我们使用命令

top -Hp 156888

这个命令可以展示进程内最消耗CPU的线程,可以得到如下结果

top - 20:00:25 up 118 days,  6:16,  2 users,  load average: 3.00, 2.91, 2.14
Tasks:  39 total,   1 running,  38 sleeping,   0 stopped,   0 zombie
Cpu(s):  9.3%us,  3.5%sy,  0.0%ni, 87.2%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  132103700k total, 76578608k used, 55525092k free,   424052k buffers
Swap: 16383996k total,        0k used, 16383996k free, 36290948k cached

   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                             
156926 hdfs      20   0 34.9g 544m  11m R 99.8  0.4  16:43.39 java                                                                                                                                                 
156901 hdfs      20   0 34.9g 544m  11m S  0.3  0.4   0:00.16 java                                                                                                                                                 
156888 hdfs      20   0 34.9g 544m  11m S  0.0  0.4   0:00.00 java                                                                                                                                                 
156889 hdfs      20   0 34.9g 544m  11m S  0.0  0.4   0:00.12 java                                                                                                                                                 
156890 hdfs      20   0 34.9g 544m  11m S  0.0  0.4   0:00.16 java                                                                                                                                                 
156891 hdfs      20   0 34.9g 544m  11m S  0.0  0.4   0:00.17 java                                                                                                                                                 
156892 hdfs      20   0 34.9g 544m  11m S  0.0  0.4   0:00.18 java                                                                                                                                                 
156893 hdfs      20   0 34.9g 544m  11m S  0.0  0.4   0:00.17 java

排名第一的便是我们这个进程下面的线程号了。

接下来,我们使用一个java中的jstack命令去定位哪一行:

jstack 156888

这样子直接获取信息内容是这样子的:

"Service Thread" #17 daemon prio=9 os_prio=0 tid=0x00002b47080f6800 nid=0x264fc runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread11" #16 daemon prio=9 os_prio=0 tid=0x00002b47080f3800 nid=0x264fb waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread10" #15 daemon prio=9 os_prio=0 tid=0x00002b47080f1000 nid=0x264fa waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread9" #14 daemon prio=9 os_prio=0 tid=0x00002b47080ef000 nid=0x264f9 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread8" #13 daemon prio=9 os_prio=0 tid=0x00002b47080ed000 nid=0x264f8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

我们大致读得出这个线程号,但是我们需要定位最消耗cpu的那个线程,我们看到nid项其实就是线程号,不过是16进制输出的,所以我们也要把我们的线程号转换成16进制,可以直接用计算器,没问题,我这里用linux下面打印命令:

printf "%x\n" 156926

结果为:

264fe

这个时候我们可以用这个数字结合我们的jstack命令去查询了:

jstack 156888 |grep 264fe

我们这样子可以搜索到这个线程,但是只有一行结果

"thread1" #18 prio=5 os_prio=0 tid=0x00002b4708167000 nid=0x264fe runnable [0x00002b4723545000]

我们可以在grep前后增加要显示的行数,可以看到上下文的内容,完整命令如下:

jstack 156888 |grep -A 20 -B 10 264fe 

我们可以输出我们要的结果

"thread1" #18 prio=5 os_prio=0 tid=0x00002b4708167000 nid=0x264fe runnable [0x00002b4723545000]
   java.lang.Thread.State: RUNNABLE
        at java.io.FileOutputStream.writeBytes(Native Method)
        at java.io.FileOutputStream.write(FileOutputStream.java:326)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        - locked <0x0000000080208ea8> (a java.io.BufferedOutputStream)
        at java.io.PrintStream.write(PrintStream.java:482)
        - locked <0x00000000802048c0> (a java.io.PrintStream)
        at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
        at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
        at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
        - locked <0x00000000802048a8> (a java.io.OutputStreamWriter)
        at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
        at java.io.PrintStream.write(PrintStream.java:527)
        - eliminated <0x00000000802048c0> (a java.io.PrintStream)
        at java.io.PrintStream.print(PrintStream.java:669)
        at java.io.PrintStream.println(PrintStream.java:806)
        - locked <0x00000000802048c0> (a java.io.PrintStream)
        at Demo1_16.lambda$main$0(Demo1_16.java:6)
        at Demo1_16$$Lambda$1/834600351.run(Unknown Source)

从内容上面看,我们尅看到是在第6行代码上面有个打印,我把完整代码贴出来:

public class Demo1_16 {
    public static void main(String[] args) {
       new Thread(()->{
           while (true){
               System.out.println("hi!");
           }
       },"thread1").start();
    }
}

可以看到是有个死循环导致的,至于为什么有三个占用最高的,那是因为我同时启动了三个这个程序。

我们把命令可以直接连起来:

jstack 156888 |grep `printf "%x" 264fe` -C6 --color

总结:

要定位最消耗的代码,我们的思路是缩小范围,顺序是进程->线程->代码,最后再看实际代码去解决问题

目录
相关文章
|
10月前
|
监控 Java Unix
6个Java 工具,轻松分析定位 JVM 问题 !
本文介绍了如何使用 JDK 自带工具查看和分析 JVM 的运行情况。通过编写一段测试代码(启动 10 个死循环线程,分配大量内存),结合常用工具如 `jps`、`jinfo`、`jstat`、`jstack`、`jvisualvm` 和 `jcmd` 等,详细展示了 JVM 参数配置、内存使用、线程状态及 GC 情况的监控方法。同时指出了一些常见问题,例如参数设置错误导致的内存异常,并通过实例说明了如何排查和解决。最后附上了官方文档链接,方便进一步学习。
1638 4
|
7月前
|
Arthas 监控 Java
Java死锁 如何定位?如何避免Java死锁?(图解+秒懂+史上最全)
Java死锁 如何定位?如何避免Java死锁?(图解+秒懂+史上最全)
Java死锁 如何定位?如何避免Java死锁?(图解+秒懂+史上最全)
|
9月前
|
搜索推荐 Java 定位技术
Java实现利用GeoLite2-City.mmdb根据IP定位城市的方法
在城市,国家,地区等地理位置数据获取之后,你可以依指定的业务需求,来进行进一步的数据处理。例如,你可以设计一个应用,根据用户的 IP 地址来个性化地展示内容,或者用于分析网络请求的来源等。
1654 20
|
8月前
|
Java Linux 开发者
linux 查看java的安装路径
本指南详细介绍Java环境的安装验证与配置方法,包括检查Java版本、确认环境变量JAVA_HOME是否正确配置,以及通过which和readlink命令手动定位Java安装路径。同时提供系统级环境变量配置步骤,并给出多版本管理建议。适用于Linux系统用户,特别是需要在服务器或Docker容器中部署Java环境的开发者。注意操作时需具备相应权限,确保路径设置准确无误。
|
10月前
|
监控 数据可视化 Java
调试技巧 - 用Linux命令排查Java问题
总的来说,使用Linux命令来排查Java问题,需要一定的实践经验和理论知识。然而,只要我们愿意花时间深入了解这些工具,我们就能够熟练地使用它们来分析和解决问题。此外,这些工具只是帮助我们定位问题,真正解决问题需要我们对Java和JVM有深入的理解,并能够读懂和分析代码。
549 13
|
Java 对象存储 开发者
如何找出Java进程占用CPU高的元凶
本文记录了一次Java进程CPU占用率过高的问题和排查思路。
|
监控 算法 Java
jvm-48-java 变更导致压测应用性能下降,如何分析定位原因?
【11月更文挑战第17天】当JVM相关变更导致压测应用性能下降时,可通过检查变更内容(如JVM参数、Java版本、代码变更)、收集性能监控数据(使用JVM监控工具、应用性能监控工具、系统资源监控)、分析垃圾回收情况(GC日志分析、内存泄漏检查)、分析线程和锁(线程状态分析、锁竞争分析)及分析代码执行路径(使用代码性能分析工具、代码审查)等步骤来定位和解决问题。
301 6
|
分布式计算 Java Hadoop
linux中HADOOP_HOME和JAVA_HOME删除后依然指向旧目录
通过以上步骤,可以有效地解决 `HADOOP_HOME`和 `JAVA_HOME`删除后依然指向旧目录的问题。确保在所有相关的配置文件中正确设置和删除环境变量,并刷新当前会话,使更改生效。通过这些措施,能够确保系统环境变量的正确性和一致性。
299 1
|
存储 缓存 前端开发
JavaEE初阶——初识EE(Java诞生背景,CPU详解)
带你从零入门JAVAEE初阶,Java的发展历程认识什么是cpu,cpu的工作原理,cpu是如何进行计算的,cpu的架构,指令集,cpu的核心,如何提升cpu的算力,cpu的指令,,cup的缓存,cpu的流水线