美文网首页
3、第二部分 自动内存管理-第4章 虚拟机性能监控、故障处理工具

3、第二部分 自动内存管理-第4章 虚拟机性能监控、故障处理工具

作者: 站得高看得远 | 来源:发表于2021-07-16 11:46 被阅读0次

基础故障处理工具

JAVA_HOME下的bin目录包含了一系列小工具:


java的bin下小工具

jps:虚拟机进程状态工具

jps(JVM Process status Tool):可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main函数所在类)名称及这些进程的本地虚拟机唯一ID(LVMID,Local Cirtual Machine Identifier)。

jps [options] [hostid]
$ jps -l
9113 sun.tools.jps.Jps
6491 org.jetbrains.jps.cmdline.Launcher
99501 

jps工具主要选项

选项 作用
-q 只输出LVMID,省略主类的名称
-m 输出虚拟机进程启动时传递给主类main函数的参数
-l 输出主类的全名,如果进程执行的是JAR包,则输出JAR路径
-v 输出虚拟机进程启动时的JVM参数

jstat(JVM Statistics MonitoringTool)是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据。

jstat [option vmid [interval[s|ms][count]]]
jstat选项图
#2个survivor区(S0、S1,表示Survivor0、Survivor1),新生代Eden区(E),老年代(O),元空间(M)。程序运行以来共发生Minor GC(YGC,表示Young GC)1次,总耗时0.005秒;发生Full GC(FGC,表示Full GC)0次,总耗时(FGCT,表示Full GC Time)为0.000秒;所有GC总耗时(GCT,表示GC Time)为0.005秒
$ jstat -gcutil 6491
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
  0.00  53.08  22.84   0.08  96.59  95.82      1    0.005     0    0.000    0.005

jinfo:Java配置信息工具

jinfo(Configuration Info for Java)的作用是实时查看和调整虚拟机各项参数。

# jinfo [ option ] pid
$ jinfo -flag CMSInitiatingOccupancyFraction 6491
-XX:CMSInitiatingOccupancyFraction=-1

jmap:Java内存映像工具

jmap(Memory Map for Java)命令用来生成堆转储快照(称为heapdump或dump文件)。还可以查询finalize执行队列、Java堆和方法区的详细信息,如空间使用率,当前用的是哪种收集器等。

jmap [ option ] vmid

jmap工具主要选项


jmap工具主要选项
jmap -dump:format=b,file=eclipse.bin 3500

jhat:虚拟机堆转储快照分析工具

JDK提供jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照。jhat内置了一个微型的Http/Web服务器,生成堆转储快照的分析结果后,可在浏览器中查看。因为jhat比较简陋,一般使用更专业的VisualV、Eclipse Memory Analyzer和IBM HeapAnalyzer等工具。

jhat idea.bin
jhat示意图

jstack:Java堆栈追踪工具

jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是定位线程出现长时间卡顿的原因,如线程间死锁、死循环、请求外部资源导致长时间挂起等。

jstack [ option ] vmid
jstack工具主要选项
jstack -l 6491
2021-06-10 22:10:32
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode):

"Attach Listener" #14 daemon prio=9 os_prio=31 tid=0x00007f8c35979000 nid=0x5707 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None
分析工具汇总

可视化故障处理工具

JConsole、JHSDB、VisualVM和JMC

JHSDB:基于服务性代理的调试工具

JHSDB是一款基于服务性代理(Serviceability Agent,SA)实现的进程外调试工具。服务性代理是HotSpot虚拟机中一组用于映射Java虚拟机运行信息的、主要基于Java语言(含少量JNI代码)实现的API集合。

#jps获取进程id,进入java目录并执行命令,进入图形界面,点击File菜单输入进程id进入界面
sudo java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB
JHSDB
import java.io.IOException;

/**
 * staticObj、instanceObj、localObj存放在哪里?
 */
public class JHSDB_TestCase {
    static class Test {
        static ObjectHolder staticObj = new ObjectHolder();
        ObjectHolder instanceObj = new ObjectHolder();

        void foo() {
            ObjectHolder localObj = new ObjectHolder();
            System.out.println("done");//这里设置一个断点

        }
    }

    private static class ObjectHolder {
    }

    public static void main(String[] args) throws IOException {
        Test test = new JHSDB_TestCase.Test();
        test.foo();
    }
}

JConsole:Java监视与管理控制台

JConsole(Java Monitoring and Management Console)是一款基于JMX(Java Management Extensions)的可视化监视、管理工具。主要功能是通过JMX的MBean(Managed Bean)对系统进行信息收集和参数动态调整。

  1. 启动JConsole
#进入java安装目录下的bin
jconsole
JConsole示意图
  1. 内存监控
    内存页签的作用相当于jstat命令,用于监视被收集器管理的虚拟机内存(被收集器直接管理的Java堆和被间接管理的方法区)的变化趋势。
import java.util.ArrayList;

/**
 * VM参数:-Xms100m -Xmx100m -XX:+UseSerialGC
 * 以64KB/50ms的速度向Java堆中填充数据,一共填充1000次
 * 内存占位符对象,一个OOMObject大约占64KB
 */
public class JConsoleTest {
    static class OOMObject {
        public byte[] placeholder = new byte[64 * 1024];
    }

    public static void fillHeap(int num) throws InterruptedException {
        ArrayList<OOMObject> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            // 稍作延时,令监视曲线的变化更加明显
            Thread.sleep(50);
            list.add(new OOMObject());
        }

        System.gc();
    }

    public static void main(String[] args) throws InterruptedException {
        fillHeap(1000);
    }
}

在“内存”页签中可以看到内存池Eden区的运行趋势呈现折线状,监视范围扩大至整个堆后,会发现曲线是一直平滑向上增长的。在循环1000次后,执行System.gc()后,虽然整个新生代Eden和Survivor区都基本被清空了,但是代表老年代的柱状图仍然保持峰值状态,说明被填充进堆中的数据在System.gc()方法执行之后仍然存活。


内存

System.gc()之后,空间未被回收是因为list对象仍然存活,fillHeap方法仍然没有退出,因此list对象在System.gc()执行时仍然处于作用域之内。将代码书写在作用域外即可。

import java.util.ArrayList;

/**
 * VM参数:-Xms100m -Xmx100m -XX:+UseSerialGC
 * 以64KB/50ms的速度向Java堆中填充数据,一共填充1000次
 * 内存占位符对象,一个OOMObject大约占64KB
 */
public class JConsoleTest {
    static class OOMObject {
        public byte[] placeholder = new byte[64 * 1024];
    }

    public static void fillHeap(int num) throws Exception {
        ArrayList<OOMObject> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            // 稍作延时,令监视曲线的变化更加明显
            Thread.sleep(50);
            list.add(new OOMObject());
        }

//        System.gc();
    }

    public static void main(String[] args) throws Exception {
        fillHeap(1000);
        System.gc();
        System.in.read();
    }
}
  1. 线程监控
    "线程"页签相当于可视化的jstack命令。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BusyAndLockThreadTest {
    /**
     * 线程死循环演示
     */
    public static void createBusyThread() {
        new Thread(() -> {
            while (true);//41行
        }, "testBusyThread").start();
    }

    /**
     * 线程锁等待演示
     * @param lock
     */
    public static void createLockThread(final Object lock) {
        new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "testLockThread").start();
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        br.readLine();
        createBusyThread();
        br.readLine();
        Object lock = new Object();
        createLockThread(lock);
//        System.in.read();
    }
}


//Integer.valueOf(a)会对数值为-128-127的Integer对象缓存,容易发生死锁
public class DeadLockTest {
    static class SynAddRunnable implements Runnable {
        int a, b;

        public SynAddRunnable(int a, int b) {
            this.a = a;
            this.b = b;
        }

        @Override
        public void run() {
            synchronized (Integer.valueOf(a)) {
                System.out.println(a + b);
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10000; i++) {
            new Thread(new SynAddRunnable(1, 2)).start();
            new Thread(new SynAddRunnable(2, 1)).start();
        }
    }
}

VisualVM:多合-故障处理工具

VisualVM(All-in-One Java Troubleshooting Tool)是功能最强大的运行监视和故障处理程序之一。
VisualVM兼容范围与插件安装

  • 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)

  • 监视应用程序的处理器、垃圾收集、堆、方法区以及线程的信息(jstat、jstack)

  • dump 以及分析堆转储快照(jmap 、jhat )

  • 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法

  • 离线程序快照:收集程序的运行时配置、线程dump 、内存dump 等信息建立一个快照,可以将快 照发送开发者处进行Bug反馈

  1. 生成、浏览堆转储快照
  • 堆dump方式


    堆dump方式
  • 堆dump后分析


  1. 分析程序性能


Java Mission Control:可持续在线的监控工具

#进入java安装目录,执行jmc

可远程连接


源自书籍:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)-周志明

相关文章

网友评论

      本文标题:3、第二部分 自动内存管理-第4章 虚拟机性能监控、故障处理工具

      本文链接:https://www.haomeiwen.com/subject/qwnvpltx.html