写点什么

几分钟搞定 Java 程序 CPU 飙升场景

作者:HelloGeek
  • 2023-09-19
    河南
  • 本文字数:1831 字

    阅读完需:约 6 分钟

一直想部署 Java 环境测试一下 CPU 或内存飙升场景,实操问题定位。自己如果部署虚拟机+安装 Linux 环境+配置 java 环境,太费劲了。幸好有 Docker 容器技术,装一个 docker desktop,直接下载所需镜像,及省劲又快捷。

准备

  1. 配置好 JDK 的 Linux 运行时环境;

  2. 一段 Bug 代码使 CPU 飙升;

  3. 查找问题的解决方案。

下载镜像

下载 JDK8 的 Linux 容器镜像环境


docker pull java:8 
复制代码


查看是否下载完成


docker imagesREPOSITORY                           TAG             IMAGE ID       CREATED         SIZEjava                                 8               d23bdf5b1b1b   6 years ago     643MB
复制代码

启动镜像

由于是一个比较纯净的镜像,没有 vim 等指令,所以我们将本地 Bug 代码 mount 到镜像中,可以很方便的进行测试。启动镜像并将/Users/xxx/workspaceforjava本地路径 mount 到镜像中/root/workspaceforjava下,/Users/xxx/workspaceforjava`中的本地文件就可以在镜像的/root/workspaceforjava 下看到。


docker run -d -it --name java-8  --mount type=bind,source=/Users/xxx/workspaceforjava,target=/root/workspaceforjava java:8
复制代码


进入镜像中。


docker exec -it java-8 /bin/bash
复制代码

Bug 代码

一段死锁代码


package com.example.demo;
import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;
public class DemoApplication { public static void main(String[] args) { Lock lock1=new ReentrantLock(); //线程t1中 new Thread(()->{ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } while (!lock1.tryLock()){ System.out.println("线程1 一直自旋获取锁"); } System.out.println("线程1 获取到锁 do something"); }).start();
// 线程2 new Thread(()->{ lock1.lock(); //此时线程2 获取到锁 但是一直阻塞 导致锁无法释放 while (true){
} }).start(); }}
复制代码


存放在/Users/xxx/workspaceforjava/dome/demo-start/src/main/com/example/demo/DemoApplication 下,也可以不按照这么放置,但在执行时需要带上 package 包名路径,如下面的指令。

编译并执行代码

javac -d . DemoApplication.javajava com.example.demo.DemoApplication
复制代码

定位查询操作

通过top命令,可以看到 PID 为 71 的进程 CPU 使用率达到 98.9%。


top - 03:25:33 up  2:07,  0 users,  load average: 5.22, 1.64, 0.74Tasks:   5 total,   1 running,   4 sleeping,   0 stopped,   0 zombie%Cpu(s): 31.6 us, 63.5 sy,  0.0 ni,  4.6 id,  0.0 wa,  0.0 hi,  0.4 si,  0.0 stKiB Mem:   4028960 total,  3532528 used,   496432 free,   349412 buffersKiB Swap:  1048572 total,        0 used,  1048572 free.  2079136 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 71 root 20 0 3354712 45896 16820 S 98.9 1.1 0:44.28 java 1 root 20 0 21948 3328 3024 S 0.0 0.1 0:00.03 bash
复制代码


使用top -H -n 1 -p 71可以看到,PID 为 84 和 85 的占用 CPU 比较高。


top - 03:25:58 up  2:08,  0 users,  load average: 5.57, 2.01, 0.89Threads:  15 total,   2 running,  13 sleeping,   0 stopped,   0 zombie%Cpu(s):  3.3 us,  3.0 sy,  0.0 ni, 93.3 id,  0.1 wa,  0.0 hi,  0.2 si,  0.0 stKiB Mem:   4028960 total,  3537752 used,   491208 free,   349532 buffersKiB Swap:  1048572 total,        0 used,  1048572 free.  2079456 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 84 root 20 0 3354712 45416 16820 R 34.6 1.1 0:29.71 java 85 root 20 0 3354712 45416 16820 R 23.1 1.1 0:38.58 java
复制代码


使用jstack -l 71 > ./jstack.log将 jstack 信息打印到 jstack.log 中。将 10 进制的 85 转化为 16 进制后为 55,通过 cat 和 grep 打印出包括 54 的后 10 行信息。


cat ./jstack.log | grep -A 10 "55"
复制代码



这样就定位到问题代码,方便下一步优化解决。


参考:


发布于: 刚刚阅读数: 3
用户头像

HelloGeek

关注

攻城攻城还需要一个师 2018-07-09 加入

混迹互联网多年,有一点心得,有一点体会。

评论

发布
暂无评论
几分钟搞定Java程序CPU飙升场景_Java_HelloGeek_InfoQ写作社区