VisualVM

  • VisualVM介绍
  • 实操
  • JVM基本配置参数
  • 总结


VisualVM介绍

VisualVM是jdk自带的监控线程,内存使用情况,查看方法的CPU时间和内存中的对象,GC等等。

搜索jvisualvm.exe,双击打开

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++


1.打开之后,主界面

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_02

2.根据需要可以安装不同的插件,点击工具——插件——可用插件。

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_03


3.我这里可用插件是零个,为什么呢?原来是插件没有更新,点击设置——打开链接——选择自己目前jdk版本号一致的链接——复制到设置里面——点击确定——可以看到可用插件里面有18个插件可以使用了。

java 查看jvm启动时加载jar的顺序 jvm查看工具_java_04


java 查看jvm启动时加载jar的顺序 jvm查看工具_System_05


java 查看jvm启动时加载jar的顺序 jvm查看工具_System_06


4.下载插件——安装——完成。

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_07


java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_08

实操

1.写一个内存泄露

package visualVM;

import java.util.HashMap;
import java.util.Map;

public class CyclicDependencies {
    private static final Map map = new HashMap();

    public static void main(String args[]) {
        try {
            //给打开visualvm时间
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //循环添加对象到缓存
        for (int i = 0; i < 1000000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("first");
        //为dump出堆提供时间
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 1000000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("second");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 3000000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("third");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 4000000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("forth");
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("qqqq");
    }
}

2.设置参数

-Xms512m -Xmx512m -XX:-UseGCOverheadLimit -XX:MaxPermSize=50m

java 查看jvm启动时加载jar的顺序 jvm查看工具_System_09


3.first打印的old区

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_10


4.forth打印的old区

java 查看jvm启动时加载jar的顺序 jvm查看工具_java_11


5.如何确定是那个对象内存泄露了?打开抽样器标签,如下图

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_12


6.按照程序输出进行堆dump,当输出second是,生成一次dump,当forth的时候,再生成一次dump,对比两次的dump内容,操作如下图。

java 查看jvm启动时加载jar的顺序 jvm查看工具_java_13


java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_14


java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_15


对比结果:两次间隔时间内TestMemory对象实例一直在增加并且多了,说明该对象引用的方法可能存在内存泄漏。如何查看对象引用关系呢?

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_16


7.右键选择类TestMemory,选择“在实例视图中显示”。

java 查看jvm启动时加载jar的顺序 jvm查看工具_i++_17


8.左侧是创建的实例总数,右侧上部分是实例的结构,下部分是引用说明,从途中可以看出类CyclicDependencies里面被引用了,并且被HashMap引用。如此可以确定泄漏的位置,进而根据实际情况进行分析解决。

java 查看jvm启动时加载jar的顺序 jvm查看工具_java_18

JVM基本配置参数

  • -Xms :初始大小内存,默认为物理内存1/64 等价于-XX:MaxHeapSize
  • -Xmx:最大分片内存,,默认为物理内存的1/4 等价于-XX:MaxHeapSize
  • -Xss :设置单个线程栈的大小,一般默认为512k~1024k
  • -Xmn :设置年轻代大小
  • -XX:MetaspaceSize :设置元空间大小
  • -XX:+PrinttGCDetails :输出详细GC收集日志信息 GC FullGC
  • -XX:SurvivorRatio :设置新生代中eden和s0/s1空间的比例 8:1:1
  • -XX:NewRatio :配置年轻代与老年代在堆结构的占比
  • -XX:MaxTenuringThreshold :默认值15,最后对象还存活,存入到老年代

总结

仅供参考,如果您有不同想法,留言板交流。