如何利用 JConsole观察分析Java程序的运行,进行排错调优

一、JConsole是什么

    从Java 5开始 引入了 JConsole。JConsole 是一个内置 Java 性能分析器,可以从命令行或在 GUI shell 中运行。您可以轻松地使用 JConsole(或者,它更高端的 “近亲” VisualVM )来监控 Java 应用程序性能和跟踪 Java 中的代码。

二、如何启动JConsole

  1. 如果是从命令行启动,使 JDK 在 PATH 上,运行 jconsole 即可。
  2. 如果从 GUI shell 启动,找到 JDK 安装路径,打开 bin 文件夹,双击 jconsole

    当分析工具弹出时(取决于正在运行的 Java 版本以及正在运行的 Java 程序数量),可能会出现一个对话框,要求输入一个进程的 URL 来连接,也可能列出许多不同的本地 Java 进程(有时包含 JConsole 进程本身)来连接。如图所示:


想分析那个程序就双击那个进程。

三、如何设置JAVA程序运行时可以被JConsolse连接分析

  1. 本地程序(相对于开启JConsole的计算机),无需设置任何参数就可以被本地开启的JConsole连接(Java SE 6开始无需设置,之前还是需要设置运行时参数 -Dcom.sun.management.jmxremote )
  2. 无认证连接 (下面的设置表示:连接的端口为8999、无需认证就可以被连接)
    Java代码 复制代码  收藏代码
    1. -Dcom.sun.management.jmxremote.port=8999 \   
    2. -Dcom.sun.management.jmxremote.authenticate=false \   
    3. -Dcom.sun.management.jmxremote.ssl=false  
    -Dcom.sun.management.jmxremote.port=8999 \
    -Dcom.sun.management.jmxremote.authenticate=false \
    -Dcom.sun.management.jmxremote.ssl=false
     
  3. 如果考虑到安全因素,需要认证,需要安全连接,也是可以搞定的。参考:http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html#gdenv

四、JConsole如何连接远程机器的JAVA程序(举例说明)

1、写一个简单的一直运行的JAVA程序,运行在某台机器上如(192.168.0.181)

Java代码 复制代码  收藏代码
  1. java -cp . -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.managent.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false JConsoleTest  
java -cp . -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.managent.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false JConsoleTest
 

2、另外一台机器进行连接

可以直接使用命令:

Java代码 复制代码  收藏代码
  1. jconsole.exe 192.168.0.181:8999  
jconsole.exe 192.168.0.181:8999

 也可以在已经打开的JConsole界面操作 连接->新建连接->选择远程进程->输入远程主机IP和端口号->点击“连接”,如图:

 



 然后就会进入分析界面: 

性能分析

下面说说如何分析,如何使用这六个标签

  • 概述: Displays overview information about the Java VM and monitored values.
  • 内存: 显示内存使用信息
  • 线程: 显示线程使用信息
  • 类: 显示类装载信息
  • *VM摘要:*显示java VM信息
  • MBeans: 显示 MBeans.

概述

 

    概述很简单没啥说的,自己看看吧,不过值得一提的是对着图点击右键可以保存数据到CSV文件,以后可以使用其他工具来分析这些数据。

内存

    这个比较有价值,参看堆内存,非堆内存,内存池的状况总体内存的分配和使用情况以及不同的GC进行垃圾回收的次数和时间。可以手动进行GC查看内存变化。

 

   在分析JAVA内存问题进行调优时候非常有用,你要学习JVM内存模型,之后会发现这里的每个值都具有意义。

 

   GC的算法和参数对性能有显著的影响,注意垃圾回收次数、时间、以及partial GC和full GC,调整你所使用的不同GC和以及各个GC下的参数,然后在这个视图下观察,以得到好的性能。

 

这里贴一下 Java HotSpot VM garbage collector 下generational GC 的各代的划分图:

 


关于GC,可以参考:http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html

线程

    左下角显示所有的活动线程(如果线程过多,可以在下面的过滤栏中输入字符串过滤出你想要观察的线程)。点击某个显示会显示这个线程的名称、状态、阻塞和等待的次数、堆栈的信息。

 

    统计图显示的是线程数目的峰值(红色)和当前活动的线程(蓝色)。

 

   另外下面有个按钮“检测到死锁”,有时候会有用处。

没啥要说的。

VM摘要

 

也没啥要说的,看看吧,内存状况,操作系统...

MBean

这里可以有一些额外的操作。

插件

Java代码 复制代码  收藏代码
  1. jconsole -pluginpath C:\Java\jdk1.6.0_22\demo\management\JTop\JTop.jar  
jconsole -pluginpath C:\Java\jdk1.6.0_22\demo\management\JTop\JTop.jar

 

一看便知,是个什么东西。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

JVM 平台提供 Mbeans 说明

Java 2 平台 5.0 以上版本,有一组 API 可以让 Java 应用程序和允许的工具监视和管理 Java 虚拟机( JVM )和虚拟机所在的本机操作系统。该组 API java.lang.management 。可以通过这些 API 可以监控 local JVM ,同时也可以监控远端 JVM


Java 平台提供了如下一些接口用于管理 JVM 平台

ClassLoadingMXBean Java 虚拟机的类加载系统。

CompilationMXBean Java 虚拟机的编译系统。

MemoryMXBean Java 虚拟机的内存系统。

ThreadMXBean Java 虚拟机的线程系统。

RuntimeMXBean Java 虚拟机的运行时系统。

OperatingSystemMXBean Java 虚拟机在其上运行的操作系统。

GarbageCollectorMXBean Java 虚拟机中的垃圾回收器。

MemoryManagerMXBean Java 虚拟机中的内存管理器。

MemoryPoolMXBean Java 虚拟机中的内存池。

这些 Bean 我们从 ManagementFactory 类中定义。

访问 Mean 的方式有两种

  1. 直接访问 MXBean 接口

  • 通过静态工厂方法获取 MXBean 实例,从本地访问正在运行的虚拟机的 MXBean 接口。

  • 构造 MXBean 代理实例,通过调用 ManagementFactory.newPlatformMXBeanProxy 将方法调用转发到给定的 MBeanServe r 。代理通常构造为远程访问另一个正在运行的虚拟机的 MXBean

  1. 通过 MBeanServer 接口间接访问(暂时还没来的及研究)

例:

直接调用同一 Java 虚拟机内的 MXBean 中的方法。

 

Java代码 复制代码  收藏代码
  1. import java.lang.management.ManagementFactory;   
  2. import java.lang.management.OperatingSystemMXBean;   
  3. import java.lang.management.ThreadMXBean;   
  4. public class JmxLocal {   
  5.     public static void main(String[] args) {       
  6.         OperatingSystemMXBean osbean = ManagementFactory   
  7.                 .getOperatingSystemMXBean();   
  8.         System.out.println(osbean.getArch());//操作系统体系结构   
  9.         System.out.println(osbean.getName());//操作系统名字   
  10.         System.out.println(osbean.getAvailableProcessors());//处理器数目   
  11.         System.out.println(osbean.getVersion());//操作系统版本       
  12.         ThreadMXBean threadBean=ManagementFactory.getThreadMXBean();   
  13.         System.out.println(threadBean.getThreadCount());//总线程数     
  14.     }   
  15. }  
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.ThreadMXBean;
public class JmxLocal {
	public static void main(String[] args) {	
		OperatingSystemMXBean osbean = ManagementFactory
				.getOperatingSystemMXBean();
		System.out.println(osbean.getArch());//操作系统体系结构
		System.out.println(osbean.getName());//操作系统名字
		System.out.println(osbean.getAvailableProcessors());//处理器数目
		System.out.println(osbean.getVersion());//操作系统版本	
		ThreadMXBean threadBean=ManagementFactory.getThreadMXBean();
		System.out.println(threadBean.getThreadCount());//总线程数	
	}
}

使用 MXBean 代理。访问远程 Mbean

 

Java代码 复制代码  收藏代码
  1. import java.lang.management.ManagementFactory;   
  2. import java.lang.management.ThreadMXBean;   
  3. import javax.management.MBeanServerConnection;   
  4. import javax.management.remote.JMXConnector;   
  5. import javax.management.remote.JMXConnectorFactory;   
  6. import javax.management.remote.JMXServiceURL;   
  7. public class JmxRemote {   
  8.     public static void main(String[] args) {   
  9.         try {   
  10. // connect to a separate VM's MBeanServer, using the JMX RMI functionality   
  11. JMXServiceURL address = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");   
  12.             JMXConnector connector = JMXConnectorFactory.connect(address);   
  13.             MBeanServerConnection mbs = connector.getMBeanServerConnection();   
  14.             ThreadMXBean threadBean = ManagementFactory.newPlatformMXBeanProxy   
  15.             (mbs, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);   
  16.             System.out.println(threadBean.getThreadCount());//线程数量         
  17.         } catch(Exception e){   
  18.             e.printStackTrace();   
  19.         }   
  20.     }   
  21. }  
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class JmxRemote {
	public static void main(String[] args) {
		try {
// connect to a separate VM's MBeanServer, using the JMX RMI functionality
JMXServiceURL address = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");
		    JMXConnector connector = JMXConnectorFactory.connect(address);
		    MBeanServerConnection mbs = connector.getMBeanServerConnection();
		    ThreadMXBean threadBean = ManagementFactory.newPlatformMXBeanProxy
	        (mbs, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
		    System.out.println(threadBean.getThreadCount());//线程数量	    
		} catch(Exception e){
			e.printStackTrace();
		}
	}
}

如果要远程访问,被访问 Mbean 服务器首选需要 命令行选项启动远程虚拟机,这些选项设置虚拟机的相关 JMX 代理侦听请求的端口,以及起作用的安全级别

如下:

-Dcom.sun.management.jmxremote.port=9999 -- 指定端口

-Dcom.sun.management.jmxremote.authenticate=false – 指定是否需要密码验证

-Dcom.sun.management.jmxremote.ssl=false – 指定是否使用 SSL 通讯

例:我要测试下面运用程序

Java代码 复制代码  收藏代码
  1. public class Test {   
  2.     public static void main(String[] args) {   
  3.         Thread thread=new Thread();   
  4.         thread.run();   
  5.         try {   
  6.             thread.sleep(100000);   
  7.         } catch (InterruptedException e) {   
  8.             e.printStackTrace();   
  9.         }   
  10.         System.out.println("Success");   
  11.            
  12.     }   
  13. }  
public class Test {
	public static void main(String[] args) {
		Thread thread=new Thread();
		thread.run();
		try {
			thread.sleep(100000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Success");
		
	}
}

 

 

启动上面运用程序时在 VM arguments 加上如上配置

远程监控 Jboss 或者 weblogic 需要配置如下:

Jboss 设置:

  • 找到 run.bat 文件( linux 环境下是 run.sh )文件,有一行

set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME%

改成

set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME%

-Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

Weblogic 设置:

  • 找到你要监控 domain 下的 startWebLogic.cmd 文件( linux 环境下是 startWebLogic.sh )文件、将文件中

set JAVA_OPTIONS=%SAVE_JAVA_OPTIONS%

改成

set JAVA_OPTIONS=%SAVE_JAVA_OPTIONS%

-Dcom.sun.management.jmxremote.port=9998 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false


Jconsole 使用说明:

启动 jconsole

jconsole JVM 自带管理 Mbean 的图形化界面

环境变量中 path 中加上

C:\Program Files\Java\jdk1.6.0_01\bin

在控制台中敲 jconsole

一个用于连接的对话框将会打开。对话框的本地进程列出本地 JVM ,中进程的 ID

 

 

你会看到两种方式,一种是本地进程,另外一种连接方式远程进程

JConsole 成功建立连接,它从连接上的JMX 代理处获取信息,并且以下面几个标签页呈现信息。

概述 tab. 监控 JVM 主要图形

内存 tab. 内存使用信息

线程 tab. 线程使用信息

tab. 类调用信息

VM 摘要 tab. JVM 的信息

MBeans tab. 所有 MBeans 的信息

如下图:

 

MBeans tab 展示了所有以一般形式注册到 JVM 上的 MBeans MBeans tab 允许你获取所有的平台信息,包括那些不能从其他标签页获取到的信息。注意,其他标签页上的一些信息也在 MBeans 这里显示。另外,你可以使用 MBeans 标签管理你自己的应用的 MBeans 。当然你也可以添加其它工具提供的 MBeans 例如 Jboss weblogic 连接池信息

 

 

内存管理:

管理内存有如下几个Mbeans :

MemoryMXBean Java 虚拟机内存系统

MemoryManagerMXBean Java 虚拟机中的内存管理器。

MemoryPoolMXBean Java 虚拟机中的内存池。

MemoryPoolMXBean 说明:
注册到 JMX 代理的平台或者应用的 MBeans ,可以通过 MBeans 标签获取。例如 , MemoryMXBean 如下面定义

 

Java代码 复制代码  收藏代码
  1. public interface MemoryMXBean {   
  2. public MemoryUsage getHeapMemoryUsage();   
  3. public MemoryUsage getNonHeapMemoryUsage();   
  4. public int getObjectPendingFinalizationCount();   
  5. public boolean isVerbose();   
  6. public void setVerbose(boolean value);   
  7. public void gc();   
  8. }  
public interface MemoryMXBean {
public MemoryUsage getHeapMemoryUsage();
public MemoryUsage getNonHeapMemoryUsage();
public int getObjectPendingFinalizationCount();
public boolean isVerbose();
public void setVerbose(boolean value);
public void gc();
}

MemoryMXBean 包括四个属性:

  • HeapMemoryUsage. 用于描述当前堆内存使用情况的只读属性

  • NonHeapMemoryUsage. 用于描述当前的非堆内存的使用情况的只读属性

  • ObjectPendingFinalizationCount. 用于描述有多少对象被挂起以便回收。

  • Verbose. 用于动态设置 GC 是否跟着详细的堆栈信息,为一个布尔变量

内存的 MBean 支持一个操作—— GC ,此操作可以发送进行实时的垃圾回收请求。

Heap—NonHeap 内存说明:

程序运行时存储数据主要有:寄存器,堆栈,堆,常量存储,非 RAM 存储

速度由高到低。

  • 堆内存类型( Heap ): Java 虚拟机具有一个 ,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。

  • 非堆内存类型( Non-Heap ): Java 虚拟机管理堆之外的内存(称为 非堆内存 )。非堆内存包括 方法区Java 虚拟机的内部处理或优化所需的内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。

 

 

监控内存( MemoryPoolMXBean
内存标签页通过读取内存系统、内存池、垃圾回收的 MBean 来获取对内存消耗、内存池、垃圾回收的情况的统计。

主要统计随时间变化,对堆的、非堆的以及特殊内存池的统计如下图

 

右下角分别绿色竖条分别表示如下(前面三项堆内内存,后面三项非堆内内存)
Eden Space (heap)
内存最初从这个线程池分配给大部分对象。
Survivor Space (heap)
用于保存在 eden space 内存池中经过垃圾回收后没有被回收的对象。
Tenured Generation (heap)
用于保持已经在 survivor space 内存池中存在了一段时间的对象。
Permanent Generation (non-heap):
保存虚拟机自己的静态 (refective) 数据,例如类( class )和方法( method )对象。 Java 虚拟机共享这些类数据。这个区域被分割为只读的和只写的,
Code Cache (non-heap): HotSpot Java
虚拟机包括一个用于编译和保存本地代码( native code )的内存,叫做“代码缓存区”( code cache


详细信息区域

 

 

 

已经使用: 已使用:当前的内存使用量。使用的内存包括所有对象占用内存

分配 : Java 虚拟机保证能够获取到的内存量。分配内存的量可能随时间改变。 Java 虚拟机可能释放部分这里的内存给系统,相应的分配的内存这时可能少于初始化时分配的给它的量。分配量总数大于或等于已使用的内存量。

最大值 : 内存管理系统可以使用的最大内存量。这个值可以被改变或者不做设定。如果 JVM 试图增加使用的内存到大于分配量,内存分配可能失败这就是我们在起 web 服务时常出现内存不够状况

分配和最大值我们都可以在运用服务启动时指定

例如:启动时设定:

-Xms512m -Xmx1024m

-Xms512m 为分配量, 1024m 为最大分配量


垃圾回收( GarbageCollectorMXBean

提供两个接口

long getCollectionCount ()

long getCollectionTime ()
GC 时间 : 垃圾回收使用的总时间和调用垃圾回收的次数。 通过

getCollectionTime ()/ getCollectionCount ()


内存池( MemoryPoolMXBean

提供内存管理接口, API 详细介绍请看 http://gceclub.sun.com.cn/Java_Docs/jdk6/html/zh_CN/api/java/lang/management/MemoryPoolMXBean.html#setCollectionUsageThreshold%28long%29

Usage Threshold ( 使用量阈值 )

usage threshold 是内存池中一个可管理的属性。默认值由 JVM 设置。可以通过 setUsageThreshold 方法设置使用量阈值。如果阈值设置为正数,将启用此内存池中的使用量阈值超过检查。如果使用率阈值设置为零,将禁用此内存池的使用量阈值超过检查。 isUsageThresholdSupported() 方法可用于确定是否支持此功能。

Java 虚拟机在其最恰当的时候(通常在垃圾回收时)会对内存池逐个进行使用量阈值超过检查。每个内存池均维护一个使用量阈值计数,每次 Java 虚拟机检测到内存池使用量超过阈值,此值都会加 1 getUsageThresholdCount() 可以取得超过使用量阈值的次数


Collection Usage Threshold ( 回收使用量阈值 )

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

Collection usage threshold 是可进行垃圾回收的内存池的一个可配置属性。 JVM 堆一个内存池进行垃圾回收以后,此内存池中的一些内存仍然被那些没有被回收的对象占用。 collection usage threshold 仅允许你在垃圾回收后对内存进行检查。如果 JVM 发现可用内存超出 collection usage threshold ,它将会设置 CollectionUsageThresholdExceeded 属性为 true 。你可以使用 CollectionUsageThresholdSupported 属性来控制内存池释放支持 collection usage threshold.

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

usage threshold collection usage threshold Jconsole MBean 设置

如果超过设定值,内存 Tab 会出现如下:

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值