jvm监控

来源:互联网 发布:百度数据新闻网 编辑:程序博客网 时间:2024/05/19 23:24

学习java或者说使用java的人肯定对jvm不会陌生,根据最近工作需要,去网上专门学习了一下jvm监控相关的知识,看了很多的网页,此文中引用了很多,所以有些忘了记网址了,如果有作者看到了,有侵权的话,请告知删除。

好了,废话不多说,直接贴知识点。

 

Linux系统下的Jvm监控

 

一、JpsJVM Process Status Tools

语法:Jps [option] [hostid]

其中hostid默认为本机,而option选项包含以下选项

Option

Function

-q

只输出LVMID

-m

输出JVM启动时传给主类的方法

-l

输出主类的全名,如果是Jar则输出jar的路径

-v

输出JVM的启动参数

 

 

 二、jstatJVM Statistics Monitoring Tools

Jstat主要用于监控虚拟机的各种运行状态信息,如类的装载、内存、垃圾回收、JIT编译器等,在没有GUI的服务器上,这款工具是首选的一款监控工具。

 

语法jstat [option vmid [interval [s|ms] [vount] ] ]

 

参数intervalcount分别表示查询间隔和查询次数,如每1毫秒查询一次进程20445的垃圾回收情况,监控20次,命令如下所示:

jstat –gc 20445 1 20

 

选项option代表用户需要查询的虚拟机的信息,主要分为3类:类装载、垃圾

回收和运行期的编译情况,具体如下表所示:

Option

Function

-class

监视类的装载、卸载数量以及类的装载总空间和耗费时间等

-gc

监视Java堆,包含eden2survivor区、old区和永久带区域的容量、已用空间、GC时间合计等信息

-gccapcity

监视内容与-gc相同,但输出主要关注Java区域用到的最大和最小空间

-gcutil

监视内容与-gc相同,但输出主要关注已使用空间占总空间的百分比

-gccause

-gcutil输出信息相同,额外输出导致上次GC产生的原因

-gcnew

监控新生代的GC情况

-gcnewcapacity

-gcnew监控信息相同,输出主要关注使用到的最大和最小空间

-gcold

监控老生代的GC情况

-gcoldcapacity

-gcold监控信息相同,输出主要关注使用到的最大和最小空间

-gcpermcapacity

输出永久带用到的最大和最小空间

-compiler

输出JIT编译器编译过的方法、耗时信息

-printcompilation

输出已经被JIT编译的方法

 

jstat –class 20445 1 20

 

各项数据解释

Loaded:加载的类的个数。

Bytes:多字节加载。

Unloaded:卸载的类数。

Bytes:多字节的卸载。

Time:执行类加载和卸载操作的时间。

 

jstat –compiler 20445 1 20

 

各项数据解释

Compiled:执行的编译任务数。

Failed:失败的编译任务数。

Invalid:已失效的编译任务的数目。

Time:完成编译任务所花费的时间。

FailedType:上次失败编译的编译类型。

FailedMethod上次失败编译的类名和方法。

 

jstat –gc 20445 100 10

 

各项数据解释

S0C:当前Survivor 空间0容量(KB)。

S1C:当前Survivor 空间1容量(KB)。

S0USurvivor 空间0利用率(KB)。

S1USurvivor 空间1利用率(KB)。

EC:当前Eden空间容量(KB)。

EUEden空间利用率(KB)。

OC:当前Old空间容量(KB)。

OUOld空间利用率(KB)。

PC:当前Permanent空间容量(KB)。

PUPermanent空间利用率(KB)。

YGCYoung 年轻一代GC事件数。

YGCTYoung 新生代垃圾收集时间。

FGC:全部GC事件的数目。

FGCT:完全垃圾收集时间。

GCT:垃圾收集总时间。

 

 

jstat –gccapacity 2540 100 5

 

各项数据解释

NGCMN:新生代最小容量(KB)。

NGCMX:新生代最大容量(KB)。

NGC:当前新生代容量(KB)。

S0C:当前Survivor 空间0容量(KB)。

S1C:当前Survivor 空间1容量(KB)。

EC:当前Eden空间容量(KB)。

OGCMNOld老一代最小容量(KB

OGCMXOld老一代最大容量(KB

OGC:当前Old老一代容量(KB

OC:当前Old空间容量(KB)。

PGCMN:最小永久代容量

PGCMX:最大永久代容量

PGC:当前永久代容量

PC:当前永久代空间容量

YGC:年轻代GC事件数

FGC:全部GC事件数

 

jstat -gccause 2540 100 5

 

LGCC:上次GC发生的原因。

GCC:当前GC发生的原因。

 

Jstat -gcnew [线程id] [监控间隔时间] [监控打印次数]

 

S0C

S1C

S0U

S1U

TT:期限阈值。

MTT:最大期限阈值。

DSS:期望Survivor大小(KB)。

EC:当前Eden空间容量(KB)。

EUEden空间利用率(KB)。

YGCYoung 年轻一代GC事件数。

YGCTYoung 新生代垃圾收集时间。

 

Jstat -gcnewcapacity [线程id] [监控间隔时间] [监控打印次数]

 

NGCMN

NGCMX

NGC

S0CMX:最大Survivor 0 空间容量

S0C:当前Survivor 0 空间容量

S1CMX

S1C

ECMX:最大Eden 空间容量

EC

YGC

FGC

 

jstat -gcutil 2540 100 5

 

S0Survivor 0 对于当前空间总容量的利用率百分比。

S1Survivor 1对于当前空间总容量的利用率百分比。

EEden区的空间利用率百分比。

OOld区的空间利用率百分比。

PPermanent区的空间利用率百分比。

YGC

YGCT

FGC

FGCT

GCT

 

 

 

三、jinfoJVM configuration Info for Java

Jinfo的作用是实时查看虚拟机的各项参数信息jps –v可以查看虚拟机在启动时被显式指定的参数信息,但是如果你想知道默认的一些参数信息呢?除了去查询对应的资料以外,jinfo就显得很重要了。

 

语法jinfo [option] pid

Options

Function

no option

打印命令行标志和系统属性名称、值对。

-flag name

打印给定命令行标志的名称和值。

-flag [+|-]name

启用或禁用给定的布尔命令行标志。

-flag name=value

将给定的命令行标志设置为指定的值。

-flags

打印传递给JVM的命令行标志。对.

-sysprops

打印java系统属性名称值对。

-h

打印帮助信息

-help

打印帮助信息

 

 

四、jmapJVM Memory Map for Java

Jmap用于生成堆快照(heapdump)。当然我们有很多方法可以取到对应的dump信息,如我们通过JVM启动时加入启动参数 –XX:HeapDumpOnOutOfMemoryError参数,可以让JVM在出现内存溢出错误的时候自动生成dump文件,亦可以通过-XX:HeapDumpOnCtrlBreak参数,在运行时使用ctrl+break按键生成dump文件,当然我们也可以使用kill -3 pid的方式去恐吓JVM生成dump文件。Jmap的作用0久带的详细信息,如空间使用率、垃圾回收器等。其运行格式如下:

Jmap [option] vmip

Option的信息如下表所示

Option

Function

-dump

生成对应的dump信息,用法为-dump:[live,]format=b,file={fileName}

-finalizerinfo

显示在F-Queue中等待的Finalizer方法的对象(只在linux下生效)

-heap

显示堆的详细信息、垃圾回收器信息、参数配置、分代详情等

-histo

显示堆栈中的对象的统计信息,包含类、实例数量和合计容量

-permstat

ClassLoder为统计口径显示永久带的内存状态

-F

当虚拟机对-dump无响应时可使用这个选项强制生成dump快照

示例:jmap -dump:format=b,file=yhj.dump 20445

 

Jvm启动参数:

启动参数松散的聚合成三类:

行为参数Behavioral Options):用于改变jvm的一些基础行为;
性能调优Performance Tuning):用于jvm的性能调优;
调试参数Debugging Options):一般用于打开跟踪、打印、输出等jvm参数,用于显示jvm更加详细的信息;

 

行为参数:

参数及其默认值

描述

-XX:-DisableExplicitGC

禁止调用System.gc();但jvmgc仍然有效

-XX:+MaxFDLimit

最大化文件描述符的数量限制

-XX:+ScavengeBeforeFullGC

新生代GC优先于Full GC执行

-XX:+UseGCOverheadLimit

在抛出OOM之前限制jvm耗费在GC上的时间比例

-XX:-UseConcMarkSweepGC

对老生代采用并发标记交换算法进行GC

-XX:-UseParallelGC

启用并行GC

-XX:-UseParallelOldGC

Full GC启用并行,当-XX:-UseParallelGC启用时该项自动启用

-XX:-UseSerialGC

启用串行GC

-XX:+UseThreadPriorities

启用本地线程优先级

上面表格中黑体的三个参数代表着jvmGC执行的三种方式,即串行、并行、并发
串行SerialGCjvm的默认GC方式,一般适用于小型应用和单处理器,算法比较简单,GC效率也较高,但可能会给应用带来停顿;
并行ParallelGC是指GC运行时,对应用程序运行没有影响,GCapp两者的线程在并发执行,这样可以最大限度不影响app的运行;
并发ConcMarkSweepGC是指多个线程并发执行GC,一般适用于多处理器系统中,可以提高GC的效率,但算法复杂,系统消耗较大;


性能调优

参数及其默认值

描述

-XX:LargePageSizeInBytes=4m

设置用于Java堆的大页面尺寸

-XX:MaxHeapFreeRatio=70

GCjava堆中空闲量占的最大比例

-XX:MaxNewSize=size

新生成对象能占用内存的最大值

-XX:MaxPermSize=64m

老生代对象能占用内存的最大值

-XX:MinHeapFreeRatio=40

GCjava堆中空闲量占的最小比例

-XX:NewRatio=2

新生代内存容量与老生代内存容量的比例

-XX:NewSize=2.125m

新生代对象生成时占用内存的默认值

-XX:ReservedCodeCacheSize=32m

保留代码占用的内存容量

-XX:ThreadStackSize=512

设置线程栈大小,若为0则使用系统默认值

-XX:+UseLargePages

使用大页面内存

我们在日常性能调优中基本上都会用到以上黑体的这几个属性; 

 

调试参数

参数及其默认值

描述

-XX:-CITime

打印消耗在JIT编译的时间

-XX:ErrorFile=./hs_err_pid<pid>.log

保存错误日志或者数据到文件中

-XX:-ExtendedDTraceProbes

开启solaris特有的dtrace探针

-XX:HeapDumpPath=./java_pid<pid>.hprof

指定导出堆信息时的路径或文件名

-XX:-HeapDumpOnOutOfMemoryError

当首次遭遇OOM时导出此时堆中相关信息

-XX:OnError="<cmd args>;<cmd args>"

出现致命ERROR之后运行自定义命令

-XX:OnOutOfMemoryError="<cmd args>;<cmd args>"

当首次遭遇OOM时执行自定义命令

-XX:-PrintClassHistogram

遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同

-XX:-PrintConcurrentLocks

遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同

-XX:-PrintCommandLineFlags

打印在命令行中出现过的标记

-XX:-PrintCompilation

当一个方法被编译时打印相关信息

-XX:-PrintGC

每次GC时打印相关信息

-XX:-PrintGC Details

每次GC时打印详细信息

-XX:-PrintGCTimeStamps

打印每次GC的时间戳

-XX:-TraceClassLoading

跟踪类的加载信息

-XX:-TraceClassLoadingPreorder

跟踪被引用到的所有类的加载信息

-XX:-TraceClassResolution

跟踪常量池

-XX:-TraceClassUnloading

跟踪类的卸载信息

-XX:-TraceLoaderConstraints

跟踪类加载器约束的相关信息

当系统出现问题的时候,又不能使用外部跟踪工具(比如JProfiler……)的情况下,以上的这些参数就会发挥重大作用了,比如dump堆信息、打印并发锁……

 

五、

jhatJVM Heap Analysis Tool

Jhat是用来分析dump文件的一个微型的HTTP/HTML服务器,它能将生成的dump文件生成在线的HTML文件,让我们可以通过浏览器进行查阅,然而实际中我们很少使用这个工具,因为一般服务器上设置的堆、栈内存都比较大,生成的dump也比较大,直接用jhat容易造成内存溢出,而是我们大部分会将对应的文件拷贝下来,通过其他可视化的工具进行分析。启用法如下:

Jhat {dump_file}

执行命令后,我们看到系统开始读取这段dump信息,当系统提示Server is ready的时候,用户可以通过在浏览器键入http://ip地址:7000进行查询。

我们可以看到刚才生成的dump文件有多大

 

 我们来生成以下看看!

jhat yhj.dump

 

 //……..

 

 然后我们启动浏览器查看

 

 我们可以看到,很详细的类信息都被抓了出来

 

 六、

jstackJVM Stack Trace for java

Jstack用于JVM当前时刻的线程快照,又称threaddump文件,它是JVM当前每一条线程正在执行的堆栈信息的集合。生成线程快照的主要目的是为了定位线程出现长时间停顿的原因,如线程死锁、死循环、请求外部时长过长导致线程停顿的原因。通过jstack我们就可以知道哪些进程在后台做些什么?在等待什么资源等!其运行格式如下:

Jstack [option] vmid

相关的optionfunction如下表所示

Option

Function

-F

当正常输出的请求不响应时强制输出线程堆栈

-l

除堆栈信息外,显示关于锁的附加信息

-m

显示native方法的堆栈信息

示例:jstack -l 20445

 

 从JDK1.5以后,java.lang.Thread类增加了一个getAllStackTraces()方法用于获取虚拟机中的StackTraceElement对象,使用这段代码我们可以通过很简单的代码获取对应JVM的信息,下面是一个简单的示例:

 

package com.yhj.monitor;

import java.util.Map;import java.util.Set;/**

 * @Described:线程监控器

 * @author YHJ create at 2012-3-26 下午05:20:18

 * @FileNmae com.yhj.monitor.Threadmonitor.java

 */public class Threadmonitor {

 

    public static void main(String[] args) {

       Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();

       Set<Thread> set = map.keySet();

       for(Thread thread : set){

           System.out.println("检测到线程["+thread.getId()+":"+thread.getName()+"],线程详细信息:");

           for(StackTraceElement trace:map.get(thread)){

              System.out.println(trace);

           }

       }

    }

}

 

一次运行结果如下:

 

 如果我们把这个写入一个

web工程的一个监控页面上,一个小的监控线程的程序就有了, 

介绍了前面几个命令,大家也许还在担心如何记住这么多详细的参数,其实JDK为我们提供了更为强大的GUI的监控工具,囊括了上面所有的监控工具的功能,同时还增加了很多工具方便我们的故障分析与性能监控!

JDK1.5开始,JDK加入了可视化监控工具Jconsole,而从JDK1.6u7以后加了了多功能于一体的可视化监控工具VisualVM。下面我们来逐一看一下!

一、JConsoleJVM Monitoring and management console

JDKbin目录下,我们很容易找到jconsole.exe这个程序,双击即可启动!

 

 这款工具既可以实现本地监控,亦可以实现远程监控

.

启动后界面如图所示:

 

 我们可以清楚的查看对应的CPu、内存、类和一起其他的详细信息。

在内存的tab页面,我们可以看到内存的变化。

 

 在线程tab,我们可以追踪对应线程的变化情况

 

 我们来监控一段代码:

 

package com.yhj.monitor;/**

 * @Described:死锁演示

 * @author YHJ create at 2012-3-26 下午05:46:36

 * @FileNmae com.yhj.monitor.Deadlock.java

 */public class Deadlockimplements Runnable{

    private int a;

    private int b;

    public Deadlock(int a,int b) {

       super();

       this.a = a;

       this.b = b;

    }

    @Override

    public void run() {

       synchronized (Integer.valueOf(a)) {

           synchronized (Integer.valueOf(b)) {

              System.out.println("a+b="+(a+b));

           }

       }

    }

    public static void main(String[] args) {

       for(int i = 0; i < 1000; ++i){

           new Thread(new Deadlock(1, 2)).start();

           new Thread(new Deadlock(2, 1)).start();

       }

    }

}

 

这段代码执行一段时间你会发现他不动了,如下图所示:

 

 我们使用Jconsole的线程tab,下面有一个检测死锁的按钮,点击一下

 

 

 

Jconsole很清楚的告诉我们发生了死锁,如上图所示。并且明确的告诉我们死锁线程每个线程都在干什么?什么资源导致了死锁的发生,很精确。

很多人还在迷惑,上段代码怎么可能发生死锁的?每个线程独享一个a和一个b,互不相干,怎么可能发生死锁呢?

其实发生死锁的原因是我们调用了Integer.valueOf()方法,这个方法是基于减少创建对象次数和节省内存设计的,出于这个的考虑,在[-128~127]之间的数字会被缓存掉,也就是我们循环中传输了那么多的12其实就返回的2个,当某个对象持有1,而另外一个对象持有2的时候,第一个等待2的释放,而第二个等待1的释放,因此就发生了死锁。其实这个程序的循环也是不需要的,2个线程就可能引发死锁,但是程序执行太快,概率太小,加一个1000次的循环就是为了增大这种概率。

二、VisualVM

VisualVM被成为是more in one的工具集,它可以实现以下功能点:

1  显示虚拟机的进程以及进程的配置信息和环境信息(jpsjinfo)

2  监视应用程序的CPU、内存、堆、方法区和线程信息(jstatjstack)

3  Dump以及分析dump的功能(jmapjhat)

4  离线程序快照:离线dump分析

5  方法运行性能分析,找出调用最多,运行最长的方法块

6  Plugings动态扩展功能

VisualVM因为是基于netBean开发,因此天生就具有plug大量扩展的能力,我们可以通过他的插件页面轻松安装所需要的插件!

启用VisualVM工具会很醒目的告诉我们检测到一个死锁,而不需要我们在Jconsole下手动启用检测。如下图所示:

 

 VisualVM

的插件安装图示如下图所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 在VisualVM中有一个开源的,强大的插件,叫做BTrace。这是一个很有意思的插件,假设这么一种场景,某天你的程序突然出现了某个差错,但是有没有写日志,怎么办呢?BTrace就可以通过简单的代码注入,在你不重启服务器的情况下动态加入相关的日志语句。相关示例请参见官方DEMOhttps://hg.kenai.com/hg/btrace~hg/file/d31d25ebd48b/samples

 

 

 

 

 

 

 

 

 


原创粉丝点击