• JVisualVM简介与内存泄漏实战分析


    一、JVisualVM能做什么
          VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带(java启动时不需要特定参数,监控工具在bin/jvisualvm.exe),能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。
         在JDK_HOME/bin(默认是C:Program FilesJavajdk1.6.0_13in)目录下面,有一个jvisualvm.exe文件,双击打开,从UI上来看,这个软件是基于NetBeans开发的了。
         可以进行远程和本地监控。远程监控需要打开jmx,下面内容会提到。
         其默认页面为:
    左侧分为本地和远程。双击本地中VisualVM线程,可以看到如下监控内容:
    具体的介绍参看:
    二、准备模拟内存泄漏demo
          1、定义静态变量HashMap
          2、分段循环创建对象,并加入HashMap
          代码如下:
    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 {
                Thread.sleep(10000);//给打开visualvm时间
            } 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");
        }
    }
         3、配置jvm参数如下:
              -Xms512m
    -Xmx512m
              -XX:-UseGCOverheadLimit
              -XX:MaxPermSize=50m
         4、运行程序并打卡visualvm监控
    三、使用jVisualvm分析内存泄漏
          1、查看Visual GC标签,内容如下,这是输出first的截图
                
    这是输出forth的截图:
    通过2张图对比发现:
    老生代一直在gc,当程序继续运行可以发现老生代gc还在继续:
    增加到了7次,但是老生代的内存并没有减少。说明存在无法被回收的对象,可能是内存泄漏了。
    如何分析是那个对象泄漏了呢?打开抽样器标签:点击后如下图:
    按照程序输出进行堆dump,当输出second时,dump一次,当输出forth时dump一次。
    进入最后dump出来的堆标签,点击类:
    点击右上角:“与另一个堆存储对比”。如图选择第一次导出的dump内容比较:
    比较结果如下:
    可以看出在两次间隔时间内TestMemory对象实例一直在增加并且多了,说明该对象引用的方法可能存在内存泄漏。
    如何查看对象引用关系呢?
    右键选择类TestMemory,选择“在实例视图中显示”,如下所示:
    左侧是创建的实例总数,右侧上部为该实例的结构,下面为引用说明,从图中可以看出在类CyclicDependencies里面被引用了,并且被HashMap引用。
    如此可以确定泄漏的位置,进而根据实际情况进行分析解决。
    四、jVisualvm远程监控tomcat
         1、修改远程tomcat的catalina.sh配置文件,在其中增加:
              JAVA_OPTS="$JAVA_OPTS
              -Djava.rmi.server.hostname=192.168.122.128
              -Dcom.sun.management.jmxremote.port=18999
    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.authenticate=false"
    这次配置先不走权限校验。只是打开jmx端口。
        2、打开jvisualvm,右键远程,选择添加远程主机:
              
       3、输入主机的名称,直接写ip,如下:
              
            右键新建的主机,选择添加JMX连接,输入在tomcat中配置的端口即可。
       4、双击打开。完毕!
    五、扩展知识
    线程死锁侦测
    jvm优化建议
         本质上是减少GC的次数。
    如果是频繁创建对象的应用,可以适当增加新生代大小。常量较多可以增加持久代大小。对于单例较多的对象可以增加老生代大小。比如spring应用中。
    GC选择,在JDK5.0以后,JVM会根据当前系统配置进行判断。一般执行-Server命令便可以。gc包括三种策略:串行,并行,并发。
    吞吐量大大应用,一般采用并行收集,开启多个线程,加快gc的是否。
    响应速度高的应用,一般采用并发收集,比如应用服务器。
         年老代建议配置为并发收集器,由于并发收集器不会压缩和整理磁盘碎片,因此建议配置:
         -XX:+UseConcMarkSweepGC  #并发收集年老代
         -XX:CMSInitiatingOccupancyFraction=80 # 表示年老代空间到80%时就开始执行CMS
         -XX:+UseCMSCompactAtFullCollection # 打开对年老代的压缩。可能会影响性能,但是可以消除内存碎片。 
         -XX:CMSFullGCsBeforeCompaction=10 # 由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此参数设置运行次FullGC以后对内存空间进行压缩、整理。 
    直接运行linux上的jvisualvm
         下载X-Manager,可以将试图展现在本地机器上。
    不受此jvm支持
         保证jvisualvm所属jdk版本和linux上一致。
  • 相关阅读:
    规则引擎集成接口(一)初始体验
    转载--Defunct僵尸进程
    转载--sigprocmask阻塞进程
    转载--__attribute__ 你知多少?
    转载--va_list
    转载--如何使用# ## ... _ _VA_ARGS_ _
    转载--C语言中的__FILE__、__LINE__和__func__
    转载--wait waitpid解释
    转载--c语言宏定义(1)
    转载--c语言宏定义(2)
  • 原文地址:https://www.cnblogs.com/belen/p/5573501.html
Copyright © 2020-2023  润新知