之前本来打算结合自己写的小程序来介绍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进程,当程序结束时堆内存如下:

可以看到对内存峰值在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,我们来看下运行时内存图:

会发现堆内存呈规律的折线,我们来分析下:当每个对象实例化后,然后置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个线程概率还是非常大的),我们在线程页点击“检测死锁”,则会多出来一个死锁页,打开可以看到如下信息:

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

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

JVM学习总结五(番外)——JConsole的更多相关文章

  1. JVM学习总结五(番外)——VisualVM

    距离上次介绍Jconsole已经时隔两周了,这期间由于工作中要用go来做一个新项目,所以精力都用在入门go上了,不过发现go语言用起来真的挺不错的,比python感觉还好点,大家没事可以了解下.   ...

  2. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  3. Netty学习笔记(番外篇) - ChannelHandler、ChannelPipeline和ChannelHandlerContext的联系

    这一篇是 ChannelHandler 和 ChannelPipeline 的番外篇,主要从源码的角度来学习 ChannelHandler.ChannelHandler 和 ChannelPipeli ...

  4. JVM学习总结五——性能监控及故障处理工具

    之前扯了四篇理论,这一篇终于可以动动手了.本篇我们将介绍JVM常用的一些工具,这些工具将是我们监控JVM状态.处理故障和调优分析的利器. 不过在开始之前,我还是要先车扯两句:工具终归只是帮助我们我们处 ...

  5. JVM学习(五)对象的引用类型

    一.引言 前面我们学习了JVM的垃圾回收机制,我们知道了垃圾回收是JVM的自发行为:虽然我们可以通过System.gc() 或Runtime.getRuntime().gc()进行显式调用垃圾回收 , ...

  6. java jvm学习笔记五(实践自己写的类装载器)

     欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和 ...

  7. JVM学习笔记五:虚拟机类加载机制

    类加载生命周期 类加载生命周期:加载.验证.准备.解析.初始化.使用.卸载 类加载或初始化过程什么时候开始? 遇到new.getstatic.putstatic或invokestatic这4条字节码指 ...

  8. JVM学习(五) -执行子系统

    虚拟机和物理机的区别.两种都有代码执行能力.物理机的执行引擎是建立在处理器.硬件.指令集和操作系统上.而虚拟机的执行引擎是有自己实现的.因此可以自行的制定指令集和执行引擎的结构关系. 个人理解:分为三 ...

  9. JVM学习十五 - (复习)类加载的时机、类加载过程、类加载器

    一.类加载的时机 类的生命周期 类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括以下 7 个阶段: 加载 验证 准备 解析 初始化 使用 卸载 验证.准备.解析 3 个阶段统称为连接 ...

随机推荐

  1. Andriod项目开发实战(1)——如何在Eclipse中的一个包下建新包

    最开始是想将各个类分门别类地存放在不同的包中,所以想在项目源码包中新建几个不同功能的包eg:utils.model.receiver等,最后的结果应该是下图左边这样的:   很明显建立项目后的架构是上 ...

  2. TCP/IP详解学习笔记(7)-- 初识运输层

    作为TCP和UDP协议的学习前奏,简单的介绍一下运输层的相关内容,方便对TCP,UDP的学习. 1.概述      运输层的任务主要是负责主机中两个进程之间的通信.      运输层的基本功能: 复用 ...

  3. max subquence sum(n^2)

    #include<cstdio>#include<cstring>const int maxn=100005;int buf[maxn];int main(){ freopen ...

  4. HTML与XHTML的区别

    为什么要使用XHTML? 我们认为万维网上的许多页面都包含着糟糕的 HTML 代码. 下面的 HTML 代码仍然可以工作得很好,即使它没有遵守 HTML 规则: <html> <he ...

  5. 蘑菇街iOS客户端应用源码

    蘑菇街iOS客户端应用源码 随着蘑菇街由导购向电商转型,蘑菇街自己的IM也应运而生,IM起初只是用于商家和买家之间沟通的工具.后面我们问自己,既然已经有了用于客服的IM,为什么不自己做一个IM,用于公 ...

  6. wordpress代理设置

    打开wp-config.php,在页首加上以下语句: define('WP_PROXY_HOST', '192.168.84.101'); define('WP_PROXY_PORT', '8080' ...

  7. Windows2003 IIS开启Gzip网页压缩

    1.单击"开始"-"管理工具"-"Internet 信息服务(IIS)管理器",打开IIS管理器:2.在 "IIS 管理器&quo ...

  8. c#获取多个List<class>合并、并将相同条件下的值累计sum

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. [原]Django慢请求分析工具--dogslow

    当你的网站突然变慢了,你怎么办? 先看监控,查看系统的资源消耗,CPU?IO?磁盘? 然后看日志,查看第一个出现慢请求的接口是哪个? 然后看依赖的服务,是第三方服务还是DB瓶颈,还是redis变慢,还 ...

  10. ASP.NET的错误处理机制之一(概念)

    对Web应用程序来说,发生不可预知的错误和异常在所难免,我们必须为Web程序提供错误处理机制.当错误发生时,我们必须做好两件事情:一是将错误信息记录日志,发邮件通知网站维护人员,方便技术人员对错误进行 ...