jvm 分析调优工具-学习笔记

本文介绍了JVM分析调优工具,如jps查看Java进程pid、jmap查看JVM资源情况、jinfo查看JVM和系统参数、jstat查看堆内存使用量和加载类数量。还列举了三个应用场景,包括分析OOM后的dump文件、排查程序死锁问题、找出占用CPU最高的线程堆栈信息。

jvm 分析调优工具

jps命令查看java进程pid

jps 列出java进程名(不完整类名) 和pid

在这里插入图片描述

jps -l 列出java进程名(完整类名) 和pid

在这里插入图片描述

jmap命令查看java进程占用的jvm资源情况

jmap -histo pid 查看内存情况

在这里插入图片描述

jmap -heap pid 查看java程序的堆占用信息

在这里插入图片描述

jmap -dump 导出heap快照分析文件heap.hprof

在这里插入图片描述

生成的heap.hprof文件可以使用mat工具或jvisualvm工具 进行分析。

可以在jar启动时配置 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./(指定路径)
这样就能设置内存溢出自动导出dump文件到指定的路径

mat工具是第三方厂商提供的工具,

一般使用jdk自带的jvisualvm 工具查看导出的heap.hprof文件
在这里插入图片描述

控制台输入jvisualvm命令即可打开jdk自带的可视化jvm分析工具
在这里插入图片描述

点文件->装入 ,把heap.hprof文件导入到visualVM里,就可以看到堆dump的详细信息
在这里插入图片描述

jinfo命令查看java程序的jvm参数和sys配置参数

jinfo查看java程序的jvm参数

jinfo -flags pid 可以看到程序的Xmx Xms等参数配置情况

在这里插入图片描述

jinfo查看java程序的系统参数

查看java系统参数,使用命令 jinfo -sysprops pid

在这里插入图片描述

jstat命令查看堆内存各部分的使用量已经加载类的数量

gc垃圾回收统计 jstat -gc pid

在这里插入图片描述

堆内存统计 jstat -gccapacity pid

在这里插入图片描述

新生代垃圾回收统计 jstat -gcnew pid

在这里插入图片描述

新生代内存统计 jstat -gcnewcapacity pid

在这里插入图片描述

老年代垃圾回收统计 jstat -gcold pid

在这里插入图片描述

老年代内存统计 jstat -gcoldcapacity pid

在这里插入图片描述

元数据空间统计 jstat -gcmetacapacity pid

在这里插入图片描述

垃圾回收简化 jstat -gcutil pid

在这里插入图片描述

场景1-分析线上应用OOM后生成的dump文件

线上应用的jvm启动参数配置

-Xms28m -Xmx56m -XX:+HeapDumpOnOutOfMemoryError

代码案例OOMTest.java

package cn.demo;

import java.util.ArrayList;
import java.util.List;

public class OOMTest {


    public static void main(String[] args) {
        
        List<ThirdUser>  list = new ArrayList<>();

        while (true){  //while true 死循环,会使程序一直执行
            ThirdUser thirdUser = new ThirdUser();
            thirdUser.setUsername("1");
            thirdUser.setAge(1);
            thirdUser.setHobby("ctrl");
            list.add(thirdUser); //由于配置了-Xmx56m,当程序占用的jvm内存大于56m后会报OOM
        }
    }
}

class ThirdUser {

    private String username;

    private Integer age;

    private String hobby;

    public ThirdUser() {
    }

    public ThirdUser(String username, Integer age, String hobby) {
        this.username = username;
        this.age = age;
        this.hobby = hobby;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "ThirdUser{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", hobby='" + hobby + '\'' +
                '}';
    }
}

启动运行后,会报错OutOfMemoryError

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid5768.hprof ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at cn.demo.OOMTest.main(OOMTest.java:18)
Heap dump file created [106019329 bytes in 0.408 secs]

在这个java程序根目录下会生成 dump文件 java_pid5768.hprof ,然后,使用jvisualvm 或 jprofiler 工具进行分析hprof文件。

这里以jvisualvm工具为例,把java_pid5768.hprof导入到jvisualvm后,可以看到如下界面
在这里插入图片描述

在这里插入图片描述

场景2-利用jstack命令排查程序死锁问题

代码案例MustDeadLockDemo.java

package cn.demo;

public class MustDeadLockDemo {

    static class DeadLockTask implements Runnable{
        private boolean flag;
        private Object lock1;
        private Object lock2;
        public DeadLockTask(boolean flag, Object lock1, Object lock2) {
            this.flag = flag;
            this.lock1 = lock1;
            this.lock2 = lock2;
        }
        @Override
        public void run() {
            if (flag){
                synchronized (lock1){
                    System.out.println(Thread.currentThread().getName()+"->拿到锁1");
                    try {
                        Thread.sleep(1000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"->等待锁2释放...");
                    synchronized (lock2){
                        System.out.println(Thread.currentThread().getName()+"->拿到锁2");
                    }
                }
            }
            if (!flag){
                synchronized (lock2){
                    System.out.println(Thread.currentThread().getName()+"->拿到锁2");
                    try {
                        Thread.sleep(1000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"->等待锁1释放...");
                    synchronized (lock1){
                        System.out.println(Thread.currentThread().getName()+"->拿到锁1");
                    }
                }
            }
        }
    }

    public static void main(String[] args){
        Object lock1 = new Object();
        Object lock2 = new Object();
        new Thread(new DeadLockTask(true,lock1,lock2),"线程1").start();
        new Thread(new DeadLockTask(false,lock1,lock2),"线程2").start();
    }
}

这个程序执行会因为拿不到对方的锁而一直阻塞,无法结束。

首先使用 jps命令找到这个java进程的pid

jps -l

然后使用jstack 命令查看这个java进程的线程dump信息

jstack pid

在这里插入图片描述

在这里插入图片描述

解决死锁的办法:打破多线程对资源的死锁占用,使其存在先后执行、先后占用的顺序。

场景3-使用jstack找出占用cpu最高的线程堆栈信息

代码案例CpuMaxTest.java

package cn.demo;

public class CpuMaxTest {
    public static final int initData = 66;
    public static UserTest user = new UserTest();
    private UserTest user2 = new UserTest();
    public int compute(){
        int a =1;
        int b =2;
        int c = (a+b)*10;
        return c;
    }
    public static void main(String[] args) {
        CpuMaxTest test = new CpuMaxTest();
        while (true){
            test.compute();
        }
    }
}

class UserTest {
    private String uid;
    private String name;
    UserTest() {
    }
    UserTest(String uid, String name) {
        this.uid = uid;
        this.name = name;
    }
}

这个程序执行后会导致CPU占用 99%,排查步骤如下

1用 jps -l 列出java进程的进程号 和 进程名

jps -l

在这里插入图片描述

2使用命令 top -p pid ,查看这个java进程在linux的内存情况,pid是你的java进程号

top -p  8318

在这里插入图片描述

3按大写的H键 ,获取每个线程的内存情况

在这里插入图片描述

4找到内存和CPU占用最高的线程tid ,比如1804

5将1804转换成16进制,使用命令

printf '%x\n' 1804

在这里插入图片描述

6执行 如下的jstack 命令,得到线程堆栈信息中 0x2119这个线程所在行后面10行的信息。

 jstack  进程pid | grep -A 10  线程id的16进制

在这里插入图片描述

7根据上面的堆栈信息找出可能存在问题的代码。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThinkPet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值