jvm监控工具:visualVM

监控jvm工具:visualVM

为什么要监控jvm

众所周知,jvm(java virtual mechine)是java的精髓

秉持着“一次编码,到处运行”的设计理念,可以说jvm让java在90年代火到了21世纪至今

由c++开发的jvm,它巧妙地设计了java的设计理念——即万物皆对象。并设计了这些对象应该如何存储,如何调用,并通过不断迭代设计让对象的存储和回收,执行更加合理,下图是jvm的发展历程。

img

时至今日,jvm这种“虚拟机”设计来运行的语言和生态仍然丰富。比如Kotlin,Groovy,JRuby(也就是说java可能会老,但jvm不会)。

也许开发者未必精通jvm,但对jvm的深入了解可以对开发,排错,调优有非常大的帮助。这里给出最基本的 jvm 入门知识,也是你监控 jvm并期待通过分析jvm来排错调优所必要的基础知识:

  • 堆(Heap):
    • 堆是用于存储对象实例的内存区域。在堆中分配的对象包括通过 new 关键字创建的对象以及数组。
    • 所有线程共享堆,但每个对象都有一个标识它的引用。
  • 栈(Stack):
    • 栈用于存储方法的局部变量、操作数栈、方法返回地址等。每个线程都有自己的栈。
    • 每个方法在执行时都会创建一个栈帧,栈帧包含了该方法的局部变量表、操作数栈、动态链接、方法返回地址等信息。
  • 程序计数器(Program Counter):
    • 程序计数器是每个线程私有的,用于存储当前线程执行的字节码指令的地址或索引。
    • 在多线程环境下,程序计数器用于记录每个线程执行的位置,确保线程切换后能够恢复到正确的执行位置。
  • 本地方法栈(Native Method Stack):
    • 本地方法栈类似于栈,但用于执行本地方法(非 Java 语言编写的方法)。
    • 本地方法栈的实现和栈类似,但用于执行本地代码。
  • 元空间(Metaspace):
    • 元空间是 JDK 8+ 版本中引入的(替代原来的方法区),使用本机内存存储类的元信息,包括类的结构信息、静态变量、方法信息等。

堆内提供垃圾回收,通过监视和清理不再使用的对象,释放内存空间,避免内存泄漏和提高程序性能

VisualVM分析

事实上,由于jvm的不断发展,官方(无论是jdk还是jvm)提供了很多命令和接口编程去帮助开发者监控jvm。

而其中本文详细介绍的VisualVM则是一款官方的,简单可视化的jvm监控工具。

下载安装

官网:https://visualvm.github.io/download.html

Q:如何汉化?

A:请从%JAVA_HOME%/bin下的jvisualvm.exe点击运行,image-20240122215152543

快速上手

首先启动一个java程序(本地)

你可以查看本地和远程 Java 应用程序的列表


​ 点击该连接,可以看到该java程序的概述页,包括该进程的PID,主机ip,运行主类,jvm参数,jvm版本,JAVA_HOME等

点击《监视》页面,可以查看该进程的类,cpu,线程活动,堆占用情况。

在这里可以手动《执行垃圾回收》,jvm会对堆进行垃圾回收,它监视和清理不再使用的对象,释放内存空间,避免内存泄漏,以此提高程序性能。

可以看到这个进程设置堆内存为238,026,784B(200多M),最大堆设置为7xxx,堆内存已使用92,573,992B(92M)。

加载的类有15000多个,线程77个。其中活动线程为42个

tips:这里包括了springboot包和项目内部的线程和类。

堆分析

通过点击《堆dump》,可以生成堆的分析文件.hprof,

image-20240122212620450

和很多软件和系统(如windows的bat,ps的psd,Android的apk)都会定制他们的格式一样,你不必管它如何打开,只需导入VisualVM即可查看文件内容

线程分析

通过点击《线程》,可以实时监控该进程的线程,如他们的状态,运行时间。

image-20240122212957205

如线程之间发生了死锁,它会对你提醒。这里模拟一个死锁程序,如下所示Thread1和Thread0会发生死锁现象(可直接copy运行)

package com.xsrmall.portal;

public class DeadlockDemo {

    public static void main(String[] args) {
        // 创建两个资源对象
        Resource resource1 = new Resource("Resource 1");
        Resource resource2 = new Resource("Resource 2");

        // 创建并启动两个线程
        Thread thread1 = new Thread(() -> {
            try {
                resource1.method1(resource2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                resource2.method2(resource1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
    }

    // 资源类
    static class Resource {
        private String name;

        public Resource(String name) {
            this.name = name;
        }

        // 获取资源1的锁,然后尝试获取资源2的锁
        public synchronized void method1(Resource otherResource) throws InterruptedException {
            System.out.println(name + " is holding " + name);
            Thread.sleep(100); // 模拟执行业务逻辑
            System.out.println(name + " is waiting for " + otherResource.name);
            otherResource.method2(this);
            System.out.println(name + " released " + otherResource.name);
        }

        // 获取资源2的锁,然后尝试获取资源1的锁
        public synchronized void method2(Resource otherResource) throws InterruptedException {
            System.out.println(name + " is holding " + name);
            Thread.sleep(100); // 模拟执行业务逻辑
            System.out.println(name + " is waiting for " + otherResource.name);
            otherResource.method1(this);
            System.out.println(name + " released " + otherResource.name);
        }
    }
}

image-20240122170035119

你可以点击《线程dump》生成线程执行的日志。

image-20240122213646372

如上所示,可以看到死锁线程和发生死锁的具体方法,这可以帮助开发者快速定位死锁问题。

tips: idea在执行这里旁边就有转储线程,image-20240122213833377image-20240122213922476

抽样器

类似vmWare的快照,它会对此时进程运行的cpu运行情况进行展示

image-20240122214201647

可以看到这个本地的part方法占用了82%的总进程cpu时间。259s。

也可以对内存进行抽样,不再赘述。

Profiler

Profiler可以进行性能分析。目前笔者不需要这个就不看了,待更新。

事实上,VisualVM的很多执行都是去执行提供的类似jmap,jps,jmx规范等jvm/jdk命令

之后会写一篇jdk和jvm提供的监控jvm的命令或java对象。

参考:

https://www.cnblogs.com/liukaifeng/p/10052647.html

https://www.jianshu.com/p/bb4ba6612392

https://heapdump.cn/article/4481245

https://www.cnblogs.com/baby123/p/11551626.html

https://www.liaoxuefeng.com/wiki/1252599548343744/1282385687609378

http://www.oracle.com/technetwork/java/javase/index-138283.html

https://visualvm.github.io/troubleshooting.html?Java_VisualVM

https://www.oracle.com/java/technologies/javase/troubleshooting-javase.html

https://www.51cto.com/article/704419.html

acle.com/technetwork/java/javase/index-138283.html

https://visualvm.github.io/troubleshooting.html?Java_VisualVM

https://www.oracle.com/java/technologies/javase/troubleshooting-javase.html

https://www.51cto.com/article/704419.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

编程就是n踢r

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

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

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

打赏作者

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

抵扣说明:

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

余额充值