zoukankan      html  css  js  c++  java
  • JVM学习总结五(番外)——JConsole

        之前本来打算结合自己写的小程序来介绍JConsole和VirtualVM的使用的,但是发现很难通过一个程序把所有的场景都体现出来,所以还是决定用书中的典型小例子来讲更加清晰。

    一、JConsole的基本功能

        JConsole是一个机遇JMX(Java Management Extensions,即Java管理扩展)的JVM监控与管理工具,监控主要体现在:堆栈内存、线程、CPU、类、VM信息这几个方面,而管理主要是对JMX MBean(managed beans,被管理的beans,是一系列资源,包含对象、接口、设备等)的管理,不仅能查看bean的属性和方法信息,还能够在运行时修改属性或调用方法。
        首先我们看下JConsole的启动,JConsole在jdk/bin/下,其启动需要图形界面的支持(废话,都说了图形界面),可能不少人一听到这个就觉得有点low:平时服务器跑的linux都没图形界面,那岂不是用不了。其实不用担心,JConsole支持远程进程监测。下边是连接界面,其实相当于jps命令:

        再来看下连接后的界面,我们打开DeadLock(一个测试死锁的示例):

    可以看到上边的选项卡正好对应各个功能。

    1、概述

        这个不介绍了,就是上图,相信大家都看的懂。

    2、内存

        在内存页我们可以看到程序运行期间JVM各个部分的内存状况,右下角是对应各个分区的内存使用柱状图,点击对应柱可查看详情,看图:

    3、线程

        该页面可以查看当前JVM进程启动了多少个线程,并能查看每个线程的状态及堆栈信息,此外还有一个功能就是能够自动检测死锁,见图:    

    4、类

        该页面其实和线程页有些相似,不过显示的是JVM加载类的信息,见图:

    5、VM概述

        这个其实没必要细说,看图就明白,显示了当前JVM的各方面信息:



    6、MBean管理

        这一部分也不细说,主要目前自己对JMX MBean不太熟悉,想要深究的就自己研究吧:

         下边来看两个小示例,分别分析内存和死锁的。

    二、两个示例

    1、内存分析

        这里我们来通过一个小程序进行一下内存分析,代码如下:

    package com.gj.jconsole;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class DataInsert {
    
        //一个OOMObject实例大概64k+
        static class OOMObject{
            public byte[] placeholder= new byte[64*1024]; 
        }
        
        public static void fillHeap() throws InterruptedException {
            List<OOMObject> list =new ArrayList<OOMObject>();
            for(int i=0;i<1000;i++){ 
                            Thread.sleep(100);
                list.add(new OOMObject());
            }
            System.gc();
        }
    
        public static void main(String[] args) throws Exception{
            fillHeap();
        }
    }

        可以看到程序向list中插入了1000个OOMObject对象,每个OOMObject大概64k,那么堆内存的峰值应该在64k*1000=64m左右,我们运行程序,并使用JConsole打开DataInsert进程,当程序结束时堆内存如下:

    aa

        可以看到对内存峰值在60-70m之间(下方已用内存为63631kb,大约63m),与我们预计的相符。下边我们来看下下边这段代码:

    package com.gj.jconsole;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.gj.jconsole.DataInsert.OOMObject;
    
    public class GCTest {
    
        // 一个OOMObject实例大概640k+
        static class OOMObject {
            public byte[] placeholder = new byte[64 * 1024*10];
        }
        
        public static void fillHeap() throws InterruptedException {
            for(int i=0;i<100;i++){
                OOMObject oOmObject =new OOMObject();
                Thread.sleep(1000);
                oOmObject=null;
            }
        }
        
        public static void main(String[] args) throws InterruptedException {
            fillHeap();
        }
    
    }

        这段代码每次新建一个OOMObject对象,在暂停1s后将其置null,我们来看下运行时内存图:
    aa

        会发现堆内存呈规律的折线,我们来分析下:当每个对象实例化后,然后置null,这时候对象并不会被回收(因为没有gc),因此内存会一直上升,但是当堆内存不够用时,会触发gc,因此内存会降低。查看VM概况可知,一共进行了18次gc,回收算法为“复制”。

    2、线程死锁

        通过Jconsole不仅可以查看线程信息,而且能够检测死锁,先来看下代码:

    package com.gj.jconsole;
    
    public class DeadLock {
    
        static class SynAddRunable implements Runnable{
            int a,b;
            public SynAddRunable(int a,int b){
                this.a= a;
                this.b= b;
            }
            @Override
            public void run() {
                synchronized (Integer.valueOf(a)) {
                    synchronized (Integer.valueOf(b)){
                        System.out.println(a+b);
                    }
                }
            }
        }
        
        /**
         * @param args
         */
        public static void main(String[] args) {
            for(int i=0;i<100;i++){
                new Thread(new SynAddRunable(1, 2)).start();
                new Thread(new SynAddRunable(2, 1)).start();
            }
        }
    }

        可以看到代码中启动200个子线程,进行1+2或2+1的计算,但是这种情况为什么会出现死锁呢?我们看到在run中出现双重sychronized,这是典型的死锁特征,但是这种情况要出现死锁前提是多线程中sychronized同步的两个对象分别都是同一个,才会造成互锁,但是Integer.valueOf(a)和Integer.valueOf(b)每次返回的不都是一个新对象吗?这里需要注意一个问题,为了节省内存,对于[-128,127]以内的转换,Integer.valueOf会将这些值从缓存直接返回,所以相同的值返回的都是同一个对象(记得看java源码的时候见过很多这种处理方法)。好了,来看下如何检查死锁。
        等程序运行一段时间之后(这种情况下形成死锁是随机的,并不能确定那两个会互锁,但是对于200个线程概率还是非常大的),我们在线程页点击“检测死锁”,则会多出来一个死锁页,打开可以看到如下信息:

    aa

    aa

        可以看到线程0和线程11互锁,同时线程199由于等待线程11释放锁,也被阻塞。

        以上就是JConsole的基本用法,还是比较简单的。但这些只是小道,工具毕竟只是辅助,关键的还是要懂得原理,学会分析,真正的能在实践中活用才好。下次将介绍更为强大的VirtualVM,敬请期待喽^_^。

  • 相关阅读:
    路飞学城Python-Day4(practise)
    事件绑定和普通事件的区别
    数组中shift(),push(),unshift(),pop()方法
    IE6中常见BUG与相应的解决办法
    apply()与call()的区别
    CSS引入的方式有哪些? link和@import的区别是?
    substring() , slice() and substr()方法
    webpack常用命令总结
    webpack
    从输入URL 到页面加载完成的过程
  • 原文地址:https://www.cnblogs.com/good-temper/p/3634782.html
Copyright © 2011-2022 走看看