性能分析神器VisualVM【转】

性能分析神器VisualVM【转】

Posted on  2015-04-17 09:37 WadeXu 阅读(5809) 评论(6) 编辑 收藏

VisualVM 是一款免费的,集成了多个 JDK 命令行工具的可视化工具,它能为您提供强大的分析能力,对 Java 应用程序作性能分析和调优。这些功能包括生成和分析海量数据、跟踪内存泄漏、监控垃圾回收器、执行内存和 CPU 分析,同时它还支持在 MBeans 上进行浏览和操做。本文主要介绍如何使用 VisualVM 进行性能分析及调优。html

 

复制代码
目录:
  准备工做
内存分析篇 内存堆Heap 永久保留区域PermGen CPU分析篇 线程分析篇 参考文献
复制代码

 

准备工做

自从 JDK 6 Update 7 之后已经做为 Oracle JDK 的一部分,位于 JDK 根目录的 bin 文件夹下,无需安装,直接运行便可。java

 

内存分析篇

VisualVM 经过检测 JVM 中加载的类和对象信息等帮助咱们分析内存使用状况,咱们能够经过 VisualVM 的监视标签对应用程序进行内存分析。web

1)内存堆Heap

首先咱们来看内存堆Heap使用状况,我本机eclipse的进程在visualVM显示以下:apache

 

随便写个小程序占用内存大的,运行一下小程序

程序以下:多线程

复制代码
package jvisualVM;

public class JavaHeapTest {
    public final static int OUTOFMEMORY = 200000000;
    
    private String oom;

    private int length;
    
    StringBuffer tempOOM = new StringBuffer();

    public JavaHeapTest(int leng) {
        this.length = leng;
       
        int i = 0;
        while (i < leng) {
            i++;
            try {
                tempOOM.append("a");
            } catch (OutOfMemoryError e) {
               e.printStackTrace();
               break;
            }
        }
        this.oom = tempOOM.toString();

    }

    public String getOom() {
        return oom;
    }

    public int getLength() {
        return length;
    }

    public static void main(String[] args) {
        JavaHeapTest javaHeapTest = new JavaHeapTest(OUTOFMEMORY);
        System.out.println(javaHeapTest.getOom().length());
    }

}
复制代码

查看VisualVM Monitor tab, 堆内存变大了app

 

在程序运行结束以前, 点击Heap Dump 按钮, 等待一下子,获得dump结果,能够看到一些Summary信息eclipse

点击Classes, 发现char[]所占用的内存是最大的jvm

 

双击它,获得以下Instances结果ide

 Instances是按Size由大到小排列的

第一个就是最大的, 展开Field区域的 values

StringBuffer类型的 全局变量 tempOOM 占用内存特别大, 注意局部变量是没法经过 堆dump来获得分析结果的。

另外,对于“堆 dump”来讲,在远程监控jvm的时候,VisualVM是没有这个功能的,只有本地监控的时候才有。

 

 ###转载注明出处:http://www.cnblogs.com/wade-xu/p/4369094.html 

 

2)永久保留区域PermGen

其次来看下永久保留区域PermGen使用状况

运行一段类加载的程序,代码以下:

复制代码
package jvisualVM;

import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class TestPermGen {
    
    private static List<Object> insList = new ArrayList<Object>();

    public static void main(String[] args) throws Exception {

        permLeak();
    }

    private static void permLeak() throws Exception {
        for (int i = 0; i < 1000; i++) {
            URL[] urls = getURLS();
            URLClassLoader urlClassloader = new URLClassLoader(urls, null);
            Class<?> logfClass = Class.forName("org.apache.commons.logging.LogFactory", true,urlClassloader);
            Method getLog = logfClass.getMethod("getLog", String.class);
            Object result = getLog.invoke(logfClass, "TestPermGen");
            insList.add(result);
            System.out.println(i + ": " + result);
        }
    }

    private static URL[] getURLS() throws MalformedURLException {
        File libDir = new File("C:/Users/wadexu/.m2/repository/commons-logging/commons-logging/1.1.1");
        File[] subFiles = libDir.listFiles();
        int count = subFiles.length;
        URL[] urls = new URL[count];
        for (int i = 0; i < count; i++) {
            urls[i] = subFiles[i].toURI().toURL();
        }
        return urls;
    }

    
}
复制代码

一个类型装载以后会建立一个对应的java.lang.Class实例,这个实例自己和普通对象实例同样存储于堆中,我以为之因此说是这是一种特殊的实例,某种程度上是由于其充当了访问PermGen区域中类型信息的代理者。

 

运行一段时间后抛OutOfMemoryError了, VisualVM监控结果以下:

 

结论:PermGen区域分配的堆空间太小,咱们能够经过设置-XX: PermSize参数和-XX:MaxPermSize参数来解决。

关于PermGen OOM深刻分析请参考这篇文章

关于Perform GC, 请参考这篇文章

这部分知识仍是比较深刻的,有空还要继续研究。

 

###转载注明出处:http://www.cnblogs.com/wade-xu/p/4369094.html 

 

CPU分析篇

CPU 性能分析的主要目的是统计函数的调用状况及执行时间,或者更简单的状况就是统计应用程序的 CPU 使用状况。

没有程序运行时的 CPU 使用状况以下图:

 

运行一段 占用CPU 的小程序,代码以下

复制代码
package jvisualVM;

public class MemoryCpuTest {

    public static void main(String[] args) throws InterruptedException {

        cpuFix();
    }


    /**
     * cpu 运行固定百分比
     * 
     * @throws InterruptedException
     */
    public static void cpuFix() throws InterruptedException {
        // 80%的占有率
        int busyTime = 8;
        // 20%的占有率
        int idelTime = 2;
        // 开始时间
        long startTime = 0;
        
        while (true) {
            // 开始时间
            startTime = System.currentTimeMillis();
            
            /*
             * 运行时间
             */
            while (System.currentTimeMillis() - startTime < busyTime) {
                ;
            }
            
            // 休息时间
            Thread.sleep(idelTime);
        }
    }
}
复制代码

查看监视页面 Monitor tab

 

太高的 CPU 使用率多是因为咱们的项目中存在低效的代码;

在咱们对程序施压的时候,太低的 CPU 使用率也有多是程序的问题。

 

点击取样器Sampler, 点击“CPU”按钮, 启动CPU性能分析会话,VisualVM 会检测应用程序全部的被调用的方法,

在CPU samples tab 下能够看到咱们的方法cpufix() 的自用时间最长, 以下图:

切换到Thread CPU Time 页面下,咱们的 main 函数这个进程 占用CPU时间最长, 以下图:

 ###转载注明出处:http://www.cnblogs.com/wade-xu/p/4369094.html 

 

线程分析篇

Java 语言可以很好的实现多线程应用程序。当咱们对一个多线程应用程序进行调试或者开发后期作性能调优的时候,每每须要了解当前程序中全部线程的运行状态,是否有死锁、热锁等状况的发生,从而分析系统可能存在的问题。

在 VisualVM 的监视标签内,咱们能够查看当前应用程序中全部活动线程(Live threads)和守护线程(Daemon threads)的数量等实时信息。

 

运行一段小程序,代码以下:

复制代码
package jvisualVM;

public class MyThread extends Thread{
    
    public static void main(String[] args) {
        
        MyThread mt1 = new MyThread("Thread a");
        MyThread mt2 = new MyThread("Thread b");
        
        mt1.setName("My-Thread-1 ");
        mt2.setName("My-Thread-2 ");
        
        mt1.start();
        mt2.start();
    }
    
    public MyThread(String name) {
    }

    public void run() {
        
        while (true) {
            
        }
    }
    

}
复制代码

 

Live threads 从11增长两个 变成13了

Daemon threads从8增长两个 变成10了 

 

VisualVM 的线程标签提供了三种视图,默认会以时间线的方式展示, 以下图:

能够看到两个咱们run的程序里启的线程:My-Thread-1 和 My-Thread-2

 

另外还有两种视图分别是表视图和详细信息视图, 这里看一下每一个Thread的详细视图:

 ###转载注明出处:http://www.cnblogs.com/wade-xu/p/4369094.html 

 

再来一段死锁的程序,看VisualVM 可否分析出来

复制代码
package jvisualVM;

public class DeadLock {
    public static void main(String[] args) {
        Resource r1 = new Resource();
        Resource r0 = new Resource();

        Thread myTh1 = new LockThread1(r1, r0);
        Thread myTh0 = new LockThread0(r1, r0);

        myTh1.setName("DeadLock-1 ");
        myTh0.setName("DeadLock-0 ");

        myTh1.start();
        myTh0.start();
    }
}

    class Resource {
        private int i;
    
        public int getI() {
            return i;
        }
    
        public void setI(int i) {
            this.i = i;
        }
        
    }

    class LockThread1 extends Thread {
        private Resource r1, r2;
    
        public LockThread1(Resource r1, Resource r2) {
            this.r1 = r1;
            this.r2 = r2;
        }
    
        @Override
        public void run() {
            int j = 0;
            while (true) {
                synchronized (r1) {
                    System.out.println("The first thread got r1's lock " + j);
                    synchronized (r2) {
                        System.out.println("The first thread got r2's lock  " + j);
                    }
                }
                j++;
            }
        }
    
    }

    class LockThread0 extends Thread {
        private Resource r1, r2;
    
        public LockThread0(Resource r1, Resource r2) {
            this.r1 = r1;
            this.r2 = r2;
        }
    
        @Override
        public void run() {
            int j = 0;
            while (true) {
                synchronized (r2) {
                    System.out.println("The second thread got r2's lock  " + j);
                    synchronized (r1) {
                        System.out.println("The second thread got r1's lock" + j);
                    }
                }
                j++;
            }
        }
    
    }
复制代码

 

打开VisualVM检测到的JVM进程,咱们能够看到这个tab在闪,VisualVM已经检测到我这个package下面的DeadLock类出错了

切换到Thread tab, 能够看到死锁了, Deadlock detected!

另外能够点击Thread Dump 线程转储,进一步分析,在这里就不赘述了,有兴趣的读者能够自行实验。

 

 

参考文献:

http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/

 

经过本文的介绍,相信读者已经对性能分析有一个初步的了解了,若是您以为本文的内容对您的学习有所帮助,您能够点击右下方的推荐按钮,您的鼓励是我创做的动力。

转载注明出处:http://www.cnblogs.com/wade-xu/p/4369094.html 

 

Teaching is learning.
相关文章
相关标签/搜索