JVM运行数据区和常用的JVM工具的使用

先说说JVM(Java虚拟机)吧。话说是一个运行平台。在编译器编译产生的class文件会在JVM中被加载和解释执行的。JVM有许多种,早期的是SUN classic VM之后出现hotspotBEA公司的JRockit、还有IBMJ9。他们都是JVM,但是我们现在接触的是Hotspot,他是SUN公司的,不过现在是Oracle公司的了。

    

1java的内存动态分配和垃圾回收机制,这两个特点是java区别c++的最大的原因。java的内存区域分成了几部分的数据区:方法区、堆、虚拟机栈、本地方法栈、程序计数器。

程序计数器:首先是线程隔离的。他可以看作是线程所执行的字节码行号的指示器。字节码解释器会根据计数器来选取将要执行的语句。注意他是线程隔离的,每条线程都有自己的程序计数器。对于单核 CPU 而言,每一时刻只能有一个线程在运行,而其他线程必须被切换出去。为此,每一个线程都必须用一个独立的程序计数器,用于记录下一条要运行的指令。各个线程之间的计数器互不影响,独立工作,是一块线程独有的内存空间。各个线程的计数器是互不影响的。这个区域是唯一没有任何规定会出现OutMemoryError的区域。

 

虚拟机栈:也是线程隔离的。就是我们平常经常说的栈。虚拟机栈用于存放函数调用堆栈信息。Java 虚拟机栈也是线程私有的内存空间,它和 Java 线程在同一时间创建,它保存方法的局部变量、部分结果,并参与方法的调用和返回。主要用来存储局部变量表、操作数栈、动态链接、方法出口等。局部变量表存放了编译期出现的基本数据类型、对象引用(在hotspot中对象的引用就是堆中对象实例的绝对地址的值)。

下面的例子展示了一个递归调用的应用。计数器 count 记录了递归的层次,这个没有出口的递归函数一定会导致栈溢出。程序则在栈溢出时,打印出栈的当前深度。

public class TestStack {
 private int count = 0;
 //没有出口的递归函数
 public void recursion(){
 count++;//每次调用深度加 1
 recursion();//递归
 }
 
 public void testStack(){
 try{
 recursion();
 }catch(Throwable e){
 System.out.println("deep of stack is "+count);//打印栈溢出的深度
 e.printStackTrace();
 }
 }
 
 public static void main(String[] args){
 TestStack ts = new TestStack();
 ts.testStack();
 }
}
结果如下:

ava.lang.StackOverflowError

at TestStack.recursion(TestStack.java:7)

at TestStack.recursion(TestStack.java:7)

at TestStack.recursion(TestStack.java:7)

at TestStack.recursion(TestStack.java:7)

at TestStack.recursion(TestStack.java:7)

at TestStack.recursion(TestStack.java:7)

at TestStack.recursion(TestStack.java:7)deep of stack is 9013

虚拟机栈在运行时使用一种叫做栈帧的数据结构保存上下文数据。在栈帧中,存放了方法的局部变量表、操作数栈、动态连接方法和返回地址等信息。每一个方法的调用都伴随着栈帧的入栈操作。相应地,方法的返回则表示栈帧的出栈操作。如果方法调用时,方法的参数和局部变量相对较多,那么栈帧中的局部变量表就会比较大,栈帧会膨胀以满足方法调用所需传递的信息。因此,单个方法调用所需的栈空间大小也会比较多。

注意:函数嵌套调用的次数由栈的大小决定。栈越大,函数嵌套调用次数越多。对一个函数而言,它的参数越多,内部局部变量越多,它的栈帧就越大,其嵌套调用次数就会减少。

 

本地方法栈:是线程隔离的,主要是为了使用本地方法服务的。在hotspot中将本地方法栈和虚拟机栈是合二为一的。本地方法栈并不是用 Java 实现的,而是使用 实现的。在 SUN 的 HotSpot 虚拟机中,不区分本地方法栈和虚拟机栈。因此,和虚拟机栈一样,它也会抛出 StackOverflowError 和 OutofMemoryError

 

堆:首先是线程共享的。主要就是存放对象实例的。同时堆也是垃圾收集机制管理的主要区域。堆用于存放 Java 程序运行时所需的对象等数据。几乎所有的对象和数组都是在堆中分配空间的。Java 堆分为新生代和老生代两个部分,新生代用于存放刚刚产生的对象和年轻的对象,如果对象一直没有被回收,生存得足够长,老年对象就被移入老年代。新生代又可进一步细分为 edensurvivor space0 和 survivor space1eden 即对象的出生地,大部分对象刚刚建立时都会被存放在这里。survivor 空间是存放其中的对象至少经历了一次垃圾回收,并得以幸存下来的。如果在幸存区的对象到了指定年龄仍未被回收,则有机会进入老年代 (tenured)。下面例子演示了对象在内存中的分配方式。

代码如下:

public class TestHeapGC {
 public static void main(String[] args){
 byte[] b1 = new byte[1024*1024/2];
 byte[] b2 = new byte[1024*1024*8];
 b2 = null;
 b2 = new byte[1024*1024*8];//进行一次新生代 GC
 System.gc();
 }
}

VM的参数设置如下:

-XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -Xms40M -Xmx40M -Xmn20M

结果输出如下:

[GC [DefNew: 9031K->661K(18432K), 0.0022784 secs] 9031K->661K(38912K),
   0.0023178 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
 Heap
 def new generation total 18432K, used 9508K [0x34810000, 0x35c10000, 0x35c10000)
 eden space 16384K, 54% used [0x34810000, 0x350b3e58, 0x35810000)
 from space 2048K, 32% used [0x35a10000, 0x35ab5490, 0x35c10000)
 to space 2048K, 0% used [0x35810000, 0x35810000, 0x35a10000)
 tenured generation total 20480K, used 0K [0x35c10000, 0x37010000, 0x37010000)
 the space 20480K, 0% used [0x35c10000, 0x35c10000, 0x35c10200, 0x37010000)
 compacting perm gen total 12288K, used 374K [0x37010000, 0x37c10000, 0x3b010000)
 the space 12288K, 3% used [0x37010000, 0x3706db10, 0x3706dc00, 0x37c10000)
 ro space 10240K, 51% used [0x3b010000, 0x3b543000, 0x3b543000, 0x3ba10000)
 rw space 12288K, 55% used [0x3ba10000, 0x3c0ae4f8, 0x3c0ae600, 0x3c610000)

以上是GC日志。理解它是很重要的。我来写一个注释版本的吧。

[GC (表示垃圾回收)[DefNew: 9031K->661K(18432K)(新生代的堆大小是:18432K,其中没有gc之前使用了9031K,gc后使用了661K), 0.0022784 secs(gc的用时)] 9031K->661K(38912K),(堆的总大小是:38912K,其中没有gc之前使用了9031K,gc后使用了661K)
   0.0023178 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
 Heap(堆的具体信息,分为新生代和老年代。新生代又分为Eden区、from survivor区和to survivor区。大小比例是8:1:1)。
 def new generation total 18432K, used 9508K [0x34810000, 0x35c10000, 0x35c10000)(新生代的大小和使用率)
 eden space 16384K, 54% used [0x34810000, 0x350b3e58, 0x35810000)(eden区的大小和使用率)
 from space 2048K, 32% used [0x35a10000, 0x35ab5490, 0x35c10000)(from survivor的大小和使用率)
 to space 2048K, 0% used [0x35810000, 0x35810000, 0x35a10000)(to survivor的大小和使用率)
 tenured generation total 20480K, used 0K [0x35c10000, 0x37010000, 0x37010000)(老年代的大小和使用率)
 the space 20480K, 0% used [0x35c10000, 0x35c10000, 0x35c10200, 0x37010000)
 compacting perm gen total 12288K, used 374K [0x37010000, 0x37c10000, 0x3b010000)
 the space 12288K, 3% used [0x37010000, 0x3706db10, 0x3706dc00, 0x37c10000)
 ro space 10240K, 51% used [0x3b010000, 0x3b543000, 0x3b543000, 0x3ba10000)
 rw space 12288K, 55% used [0x3ba10000, 0x3c0ae4f8, 0x3c0ae600, 0x3c610000)

上述输出显示 JVM 在进行多次内存分配的过程中,触发了一次新生代 GC。在这次 GC 中,原本分配在 eden 段的变量 b1 被移动到 from 空间段 (s0)。最后分配的 8MB 内存被分配在 eden 新生代。


方法区:是线程共享的。在hotspot虚拟机中方法区也属于堆的一部分。方法区用于存放程序的类元数据信息。方法区与堆空间类似,它也是被 JVM 中所有的线程共享的。方法区主要保存的信息是类的元数据。方法区中最为重要的是类的类型信息、常量池、域信息、方法信息。类型信息包括类的完整名称、父类的完整名称、类型修饰符和类型的直接接口类表;常量池包括这个类方法、域等信息所引用的常量信息;域信息包括域名称、域类型和域修饰符;方法信息包括方法名称、返回类型、方法参数、方法修饰符、方法字节码、操作数栈和方法栈帧的局部变量区大小以及异常表。总之,方法区内保持的信息大部分来自于 class 文件,是 Java 应用程序运行必不可少的重要数据。

在 Hot Spot 虚拟机中,方法区也称为永久区,是一块独立于 Java 堆的内存空间。虽然叫做永久区,但是在永久区中的对象同样也可以被 GC 回收的。只是对于 GC 的表现也和 Java 堆空间略有不同。对永久区 GC 的回收,通常主要从两个方面分析:一是 GC 对永久区常量池的回收;二是永久区对类元数据的回收。Hot Spot 虚拟机对常量池的回收策略是很明确的,只要常量池中的常量没有被任何地方引用,就可以被回收。

 

下面代码会生成大量 String 对象,并将其加入常量池中。String.intern() 方法的含义是如果常量池中已经存在当前 String,则返回池中的对象,如果常量池中不存在当前 String 对象,则先将 String 加入常量池,并返回池中的对象引用。因此,不停地将 String 对象加入常量池会导致永久区饱和。如果 GC 不能回收永久区的这些常量数据,那么就会抛出 OutofMemoryError 错误。

package www.wq.ch02;

public class permGenGC {
	 public static void main(String[] args){
	 for(int i=0;i<Integer.MAX_VALUE;i++){
	 String t = String.valueOf(i).intern();//加入常量池
	 }
	 }
}

结果显示:
[GC (Allocation Failure) [DefNew: 4416K->512K(4928K), 0.0143925 secs] 4416K->4029K(15872K), 0.0144659 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [DefNew: 4928K->511K(4928K), 0.0204818 secs] 8445K->8443K(15872K), 0.0205315 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
[GC (Allocation Failure) [DefNew: 4927K->511K(4928K), 0.0216787 secs][Tenured: 12346K->1245K(12352K), 0.0139809 secs] 12859K->1245K(17280K), [Metaspace: 84K->84K(4480K)], 0.0358838 secs] [Times: user=0.03 sys=0.00, real=0.04 secs] 
[GC (Allocation Failure) [DefNew: 4480K->512K(4992K), 0.0217371 secs] 5725K->5635K(15936K), 0.0217855 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 
[GC (Allocation Failure) [DefNew: 4992K->512K(4992K), 0.0372645 secs] 10115K->10114K(15936K), 0.0373091 secs] [Times: user=0.05 sys=0.00, real=0.04 secs] 
[GC (Allocation Failure) [DefNew: 4992K->511K(4992K), 0.0447900 secs][Tenured: 14081K->1245K(14144K), 0.0386709 secs] 14594K->1245K(19136K), [Metaspace: 84K->84K(4480K)], 0.0838196 secs] [Times: user=0.09 sys=0.00, real=0.08 secs] 
[GC (Allocation Failure) [DefNew: 4480K->511K(4992K), 0.0246358 secs] 5725K->5679K(15936K), 0.0246804 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
[GC (Allocation Failure) [DefNew: 4991K->512K(4992K), 0.0334968 secs] 10159K->10157K(15936K), 0.0335449 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 
[GC (Allocation Failure) [DefNew: 4992K->511K(4992K), 0.0471104 secs][Tenured: 14124K->1245K(14144K), 0.0474985 secs] 14637K->1245K(19136K), [Metaspace: 84K->84K(4480K)], 0.0949881 secs] [Times: user=0.09 sys=0.00, real=0.10 secs] 
[GC (Allocation Failure) [DefNew: 4480K->512K(4992K), 0.0213226 secs] 5725K->5724K(15936K), 0.0213714 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 

每当常量池饱和时,FULL GC 总能顺利回收常量池数据,确保程序稳定持续进行。


2Hotspot虚拟机对象结构

    当虚拟机遇到new指令的时候,首先检查能不能在常量池中找到该类的符号引用。顺便检查是否已被加载、解析和初始化过。如果没有就进行相应的类加载。接下来虚拟机为新对象分配内存。一般会由两种分配方式:指针碰撞和空闲列表。通常采用的是空闲列表法。

对象在内存中的布局分为3块区域:对象头、实例数据和对齐填充。

对象头:包含两部分。一是存储对象自身运行时的数据。另一部分是类型指针即对象指向它的类元数据的指针。虚拟机通过这个指针来确定这个对象是那个类的实例。

实例数据:代码中所定义的各种类型的字段。无论是从父类继承的,还是子类定义的都需要记录下来。

对齐填充:仅仅是起占位符的作用。由于hotspot VM要求对象的起始地址必须是8字节的整数倍。因此当对象实例数据没有对齐时就需要通过对齐填充来补全。


3、java按值传递的,不存在按引用传递的说法

这一点很重要是java中不存在引用传递,只有值传递。在java程序中通过栈上的reference数据来操作堆上的具体对象。reference是一个指向对象的引用。hotspot在对象的访问方式上使用的是直接地址。即reference数据存储的就是堆中对象的绝对地址的值。

目前主流的访问方式是:直接地址法和句柄访问法。hotspot采用的是直接地址法。


 4JVM的堆参数调优:

Java 堆参数总结,Java 应用程序可以使用的最大堆可以用-Xmx 参数指定。最大堆指的是新生代和老生代的大小之和的最大值,它是 Java 应用程序的堆上限。

Java 堆操作是主要的数据存储操作,总结的主要参数配置如下。

与 Java 应用程序堆内存相关的 JVM 参数有:

-Xms:设置 Java 应用程序启动时的初始堆大小;

-Xmx:设置 Java 应用程序能获得的最大堆大小;

-Xss:设置线程栈的大小;

-XXMinHeapFreeRatio:设置堆空间最小空闲比例。当堆空间的空闲内存小于这个数值时,JVM 便会扩展堆空间;

-XXMaxHeapFreeRatio:设置堆空间的最大空闲比例。当堆空间的空闲内存大于这个数值时,便会压缩堆空间,得到一个较小的堆;

-XXNewSize:设置新生代的大小;

-XXNewRatio:设置老年代与新生代的比例,它等于老年代大小除以新生代大小;

-XXSurvivorRatio:新生代中 eden 区与 survivor 区的比例;

-XXMaxPermSize:设置最大的持久区大小;

-XXTargetSurvivorRatio: 设置 survivor 区的可使用率。当 survivor 区的空间使用率达到这个数值时,会将对象送入老年代。


--------------------------------------------接下来介绍JVM的工具----------------------------------------------

现在说说java的各种工具。包括jps, jstack, jmap, jconsole, jinfo, jhat, javap等。这张图是在jdkbin文件目录下的:


下面是命令行监控的主要工具和用途:

名称    

作用

jps

JVM Process Status Tool,现实指定系统内所有的HotSpot虚拟机进程 

jstat

JVM Statistics Monitoring Tool,用于收集Hotspot虚拟机各个方面的运行参数 

jinfo

Configuration Info for Java,现实虚拟机配置信息

jmap

Memory map for java,生成虚拟机的内存转储快照

jhat

JVM heap Dunp Browser,用于分析heapdump文件,他会建立一个HTTP/HTML服务,让用户可通过浏览器查看 

jstack

Stack Track for java ,显示虚拟机线程快照


一、非可视化的工具

1、jps

    jps用来查看基于HotSpot的JVM里面中,所有具有访问权限的Java进程的具体状态, 包括进程ID,进程启动的路径及启动参数等等,与unix上的ps类似,只不过jps是用来显示java进程,可以把jps理解为ps的一个子集。 使用jps时,如果没有指定hostid,它只会显示本地环境中所有的Java进程;如果指定了hostid,它就会显示指定hostid上面的java进程,不过这需要远程服务上开启了jstatd服务,可以参看前面的jstatd章节来启动jstad服务。

命令格式 :jps [ options ] [ hostid ] 

参数说明 :

-q 忽略输出的类名、Jar名以及传递给main方法的参数,只输出pid。

-m 输出传递给main方法的参数,如果是内嵌的JVM则输出为null。

-l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径。

-v 输出传给JVM的参数。

-V 输出通过标记的文件传递给JVM的参数(.hotspotrc文件,或者是通过参数-XX:Flags=<filename>指定的文件)。

-J 用于传递jvm选项到由javac调用的java加载器中,例如,“-J-Xms48m”将把启动内存设置为48M,使用-J选项可以非常方便的向基于Java的开发的底层虚拟机应用程序传递参数。下面样例均在linux的jdk1.7下测试。

使用样例:

C:\Users\Administrator>jps
78144
102612 Jps

C:\Users\Administrator>jps -l
78144
102892 sun.tools.jps.Jps

C:\Users\Administrator>jps -q
78144
102760

C:\Users\Administrator>jps -v
78144  -Dosgi.requiredJavaVersion=1.6 -Xms40m -Xmx512m
102904 Jps -Denv.class.path=.;C:\mysql-connector-java-5.0.8\mysql-connector-java
-5.0.8-bin.jar; -Dapplication.home=D:\Java\jdk1.8.0_25 -Xms8m

2、jstat

Jstat用于监控基于HotSpot的JVM,对其堆的使用情况进行实时的命令行的统计,使用jstat我们可以对指定的JVM做如下监控:

- 类的加载及卸载情况

- 查看新生代、老生代及持久代的容量及使用情况

- 查看新生代、老生代及持久代的垃圾收集情况,包括垃圾回收的次数及垃圾回收所占用的时间

- 查看新生代中Eden区及Survior区中容量及分配情况等

jstat工具特别强大,它有众多的可选项,通过提供多种不同的监控维度,使我们可以从不同的维度来了解到当前JVM堆的使用情况。详细查看堆内各个部分的使用量,使用的时候必须加上待统计的Java进程号,可选的不同维度参数以及可选的统计频率参数。

命令格式:

jstat [ option vmid [interval][s|ms][count]]

option 参数如下面表格

Option Displays...

 

class

用于查看类加载情况的统计

compiler

用于查看HotSpot中即时编译器编译情况的统计

gc

用于查看JVM中堆的垃圾收集情况的统计

gccapacity

用于查看新生代、老生代及持久代的存储容量情况

gccause

用于查看垃圾收集的统计情况(这个和-gcutil选项一样),如果有发生垃圾收集,它还会显示最后一次及当前正在发生垃圾收集的原因。

gcnew

用于查看新生代垃圾收集的情况

gcnewcapacity

用于查看新生代的存储容量情况

gcold

用于查看老生代及持久代发生GC的情况

gcoldcapacity

用于查看老生代的容量

gcpermcapacity

用于查看持久代的容量

gcutil

用于查看新生代、老生代及持代垃圾收集的情况

printcompilation

HotSpot编译方法的统计

interval 和count 代表查询次数和间隔。

C:\Users\Administrator>jstat  -class 105244
Loaded  Bytes  Unloaded  Bytes     Time
   440   475.5        0     0.0       0.33
C:\Users\Administrator>jstat  -compiler 105244
Compiled Failed Invalid   Time   FailedType FailedMethod
      19      0       0     0.01          0
C:\Users\Administrator>jstat  -gc 105244
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU
   CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  512.0  512.0   0.0    4480.0   3225.7   10944.0     9051.4   2368.0 1757.
0  0.0    0.0      152    4.435  50      1.539    5.974

C:\Users\Administrator>jstat  -gc 105244 100 10
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU
   CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  512.0   0.0   512.0   4480.0   3763.3   10944.0     4572.6   2368.0 1757.
0  0.0    0.0      157    4.579  52      1.602    6.181
512.0  512.0   0.0   512.0   4480.0   3852.9   10944.0     4572.6   2368.0 1757.
0  0.0    0.0      157    4.579  52      1.602    6.181
512.0  512.0   0.0   512.0   4480.0   4211.3   10944.0     4572.6   2368.0 1757.
0  0.0    0.0      157    4.579  52      1.602    6.181
512.0  512.0   0.0   512.0   4480.0   4480.0   10944.0     4572.6   2368.0 1757.
0  0.0    0.0      158    4.579  52      1.602    6.181
512.0  512.0  512.0   0.0    4480.0   179.2    10944.0     9051.4   2368.0 1757.
0  0.0    0.0      158    4.611  52      1.602    6.213
512.0  512.0  512.0   0.0    4480.0   448.0    10944.0     9051.4   2368.0 1757.
0  0.0    0.0      158    4.611  52      1.602    6.213
512.0  512.0  512.0   0.0    4480.0   627.2    10944.0     9051.4   2368.0 1757.
0  0.0    0.0      158    4.611  52      1.602    6.213
512.0  512.0  512.0   0.0    4480.0   896.0    10944.0     9051.4   2368.0 1757.
0  0.0    0.0      158    4.611  52      1.602    6.213
512.0  512.0  512.0   0.0    4480.0   1254.5   10944.0     9051.4   2368.0 1757.
0  0.0    0.0      158    4.611  52      1.602    6.213
512.0  512.0  512.0   0.0    4480.0   1523.3   10944.0     9051.4   2368.0 1757.
0  0.0    0.0      158    4.611  52      1.602    6.213


表示查询系统进程为105244的java程序gc,每100毫秒查询一次,一共查询十次,显示结果每列的含义如下: 

S0C

新生代中Survivor space中S0当前容量的大小(KB)

S1C

新生代中Survivor space中S1当前容量的大小(KB)

S0U

新生代中Survivor space中S0容量使用的大小(KB)

S1U

新生代中Survivor space中S1容量使用的大小(KB)

EC

Eden space当前容量的大小(KB)

EU

Eden space容量使用的大小(KB)

OC

Old space当前容量的大小(KB)

OU

Old space使用容量的大小(KB)

PC

Permanent space当前容量的大小(KB)

PU

Permanent space使用容量的大小(KB)

YGC

从应用程序启动到采样时发生 Young GC 的次数

YGCT

从应用程序启动到采样时 Young GC 所用的时间(秒)

FGC

从应用程序启动到采样时发生 Full GC 的次数

FGCT

从应用程序启动到采样时 Full GC 所用的时间(秒)

GCT

T从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC

其他以gc开始的结果列跟gc选项结果列基本一样,这里不一一列举了。


3、jinfo

jinfo可以输出并修改运行时的java 进程的opts。用处比较简单,用于输出JAVA系统参数及命令行参数。

命令格式:

jinfo [option] pid

使用样例:

C:\Users\Administrator>jinfo  -flag  MaxNewSize  105244
-XX:MaxNewSize=89456640

二、JDK可视化工具(重点)

1、jconsole

JConsole是一个基于JMX的GUI工具,用于连接正在运行的JVM,不过此JVM需要使用可管理的模式启动。如果要把一个应用以可管理的形式启动,可以在启动是设置com.sun.management.jmxremote。

jconsole可以选择本地连接,来查看本地java程序参数,也可以连接远程机器来使用,下面连接本地看:



现在我的测试代码permGenGC.java的代码如下:

package www.wq.ch02;

 

public class permGenGC {

 public static void main(String[] args){

 for(int i=0;i<Integer.MAX_VALUE;i++){

 String t = String.valueOf(i).intern();//加入常量池

 }

 }

}

 

运行结果如下:


现在通过JConsole来观察:


堆内存使用图:


线程图:这里我只有一个main线程


类;


JVM的摘要:



2、jvisualVM

jvisualVM所谓多合一虚拟机故障处理工具,有强大的插件扩展功能,通过安装插件扩展支持,jvisualVM可以做到:

a、显示虚拟机进程及进程的配置和环境信息(jps,jinfo);

b、监视应用程序CPU、GC、堆、方法区及线程的信息(jstat、jstack);

c、dump及分析堆转储快照(jmap、jhat);

d、方法级的程序性能分析,找出调用最多,运行时间最长的方法;

.....其它通过插件可以做到的;

概述里面可以看到虚拟机版本及配置的参数等。









  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值