深入JVM学习之VisualVM 工具分析GC

深入JVM学习之VisualVM 工具分析GC

VisualVM:多合一故障处理工具

VisualVM是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,并且可以预见在未来一段时间内都是官方主力发展的虚拟机故障处理工具。他除了运行监视,故障处理外,还提供了很多其他方面的功能。如性能分析等

VisualVM基于NetBeans平台开发,因此它一开始就具备了插件扩展功能的特性,通过插件扩展支持,VisualVM可以做到:

  • 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)
  • 监视应用程序的CPU、GC、堆、方法区以及线程的信息(jstat、jstack)
  • dump以及分析堆转储快照(jmap、jhat)
  • 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法
  • 离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照发送开发者处进行Bug反馈。
  • 其他plugins的无限可能性

VisualVM使用演示

运行位置

Visualvm.exe 可以在JDK安装路径bin目录找到,运行即可监视本地Java程序

使用IDEA的同学可以安装VisualVM插件使用更方便.

深入JVM学习之VisualVM 工具分析GC_第1张图片

安装完就能看到运行处多了两个图标,点击就能启动VisualVM

测试程序

在演示之前我们先准备一段测试程序,后面用Visualvm对这段程序运行情况分析

public class TestJvm {
    public static void main(String[] args) {
        byte[] allocation1, allocation2, allocation3, allocation4, allocation5;
        //为了方便监视,这里休眠一下
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        allocation1 = new byte[4*1024*1024];
        allocation2 = new byte[1*1024*1024];
        allocation3 = new byte[4*1024*1024];
        allocation4 = new byte[4*1024*1024];
        allocation4= null;
        allocation5 = new byte[4*1024*1024];

    }
}

程序运行时参数设置

-XX:+PrintGCDetails 打印GC日志
-Xms20M 初始堆大小
-Xmx20M 最大堆大小
-Xmn10M 新生代堆大小

运行观察日志打印

[GC (Allocation Failure) [PSYoungGen: 8192K->1016K(9216K)] 8192K->1632K(19456K), 0.0040618 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 8342K->1016K(9216K)] 13054K->6684K(19456K), 0.0030396 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 6244K->5086K(9216K)] [ParOldGen: 9764K->6542K(10240K)] 16009K->11628K(19456K), [Metaspace: 9157K->9157K(1058816K)], 0.0413284 secs] [Times: user=0.20 sys=0.00, real=0.04 secs] 
[GC (Allocation Failure) [PSYoungGen: 8192K->984K(9216K)] 14734K->7526K(19456K), 0.0021684 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 9216K, used 1220K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 2% used [0x00000000ff600000,0x00000000ff63b068,0x00000000ffe00000)
  from space 1024K, 96% used [0x00000000ffe00000,0x00000000ffef6010,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6542K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 63% used [0x00000000fec00000,0x00000000ff263838,0x00000000ff600000)
 Metaspace       used 9172K, capacity 9514K, committed 9728K, reserved 1058816K
  class space    used 1090K, capacity 1186K, committed 1280K, reserved 1048576K

控制台能够观察到我们这里发生3次GC1次Full GC

VisualVM 监视

监视窗口下,可以看到CPU、堆、线程等使用情况实时监控

深入JVM学习之VisualVM 工具分析GC_第2张图片

Visual GC窗口下,可以看到年轻代和老年代的GC次数和时间使用情况

深入JVM学习之VisualVM 工具分析GC_第3张图片

抽样器点击内存抽样,可以快照实时的内存使用情况,包括实例和字节数,发生内存溢出时,可以通过字节使用情况定位原因

深入JVM学习之VisualVM 工具分析GC_第4张图片

分析dump文件

VisualVM 还可以分析堆dump文件

上面的程序我们修改下,让其发生内存溢出,然后dump堆文件

增加参数

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=java.hprof 发生内存溢出时dump堆使用情况

public class TestJvm {
    public static void main(String[] args) {
        byte[] allocation1, allocation2, allocation3, allocation4, allocation5;
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        allocation1 = new byte[4*1024*1024];
        allocation2 = new byte[1*1024*1024];
        allocation3 = new byte[4*1024*1024];
        allocation4 = new byte[4*1024*1024];
//        try {
//            Thread.sleep(10000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        allocation5 = new byte[3*1024*1024];

    }
}

发生内存溢出后,可以在项目的根目录找到我们dump的java.hprof文件

在VisualVM 文件–》装入–》选择堆dump 将java.hprof加载到Visual VM中

在概述窗口可以查看内存溢出的位置

深入JVM学习之VisualVM 工具分析GC_第5张图片

在类窗口可以看出发生内存溢出时,堆的使用情况

深入JVM学习之VisualVM 工具分析GC_第6张图片

通过上面两个窗口的内容分析,基本能够定位出内存溢出的原因,方便我们调整

VisualVM远程连接

我们上面讲的都是VisualVM监控本地的java进程,更多的场景是我们监视服务器的使用情况,我们可以通过VisualVM远程连接服务器达到监视的目的。

想要监视服务器情况,需要在服务器运行jstatd 守护进程

  1. 在 $JAVA_HOME/bin 下创建安全策略文件,命名为 jstatd.all.policy,内容如下:
grant codebase "file:${java.home}/../lib/tools.jar" {

   permission java.security.AllPermission;

};
  1. 运行 jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=xxx.xx.xx.xx (hostname 为你的 IP)
  2. 在远程处创建远程连接

深入JVM学习之VisualVM 工具分析GC_第7张图片

连接成功将就可以监视服务器的运行状况了

深入JVM学习之VisualVM 工具分析GC_第8张图片

参考资料:《深入理解Java虚拟机》

你可能感兴趣的:(Java,虚拟机)