声明:以下环境均是JDK1.8 



参考:实战Java虚拟机



 



1 GC打印参数



-XX:+PrintGC



遇到GC就会打印日志



 



-XX:+PrintGCDetails



打印更详细信息,JVM退出前会打印JVM详情



 



-XX:+PrintHeapAtGC



GC前后打印堆信息



 



-XX:+PrintGCTimeStamps



会在当前GC时,打印当前启动后的时间(比如程序启动了0.08s、0.88s之类的这个时间点)



 



-XX:+PrintGCApplicationConcurrentTime        打印程序执行时间



-XX:+PrintGCApplicationStoppedTime        打印程序结束时间



 



2 类加载/卸载的跟踪



-verbose:class



跟踪类的加载和卸载过程



 



3 堆参数配置



可用-Xms、-Xmx指定堆大小,以下是一个JVM参数设置的图:



 



JVM常用参数及用法例子_Eden/From

 



上图的参数如下:



1 新生代大小配置:-Xmn,新生代会减少老年代大小,一般设置为堆的1/3或1/4



 



2 新生代eden与from/to比例关系及效果:



------------代码----------------------------


byte[] b = null;
 
  
        for (int i = 0; i < 10; i++) {
 
  
            b = new byte[1 * 1024 * 1024];
 
  
        }


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



2.1 使用java -Xmx20m -Xms20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails NewSizeDemo  结果如下:



 



JVM常用参数及用法例子_Eden/From_02

 



- 分析:首先设置了堆的大小为20m,然后设置eden与from的比例=2,并打印了GC日志。由于这里新生代分配到3584K(Eden) + 1536K(From) = 5120K,并且循环遍历10次,每次分配1m内存,eden区到第四次就不够,要进行回收,通过GC确保新生代有足够空间。



 



2.2 把程序的new byte[1 * 1024 * 1024] 改为 new byte[5 * 1024 * 1024],这样每次会分配5M内存,3584K(Eden空间大小)无法容纳单次分配的5M大小,故所有空间分配只能分到老年代中(图中老年代可见用了大概10M,刚好是2 * (5*1024*1024)),两次内存分配,原因是老年代只有13M,最多只能容纳两次内存分配,第三次就会回收。



 



JVM常用参数及用法例子_JVM_03

 



2.3 把new byte[5 * 1024 * 1024] 改为 new byte[1 * 1024 * 1024],每次分配1m内存。然后使用参数如下:



# java -Xmx20m -Xms20m -Xmn15m -XX:SurvivorRatio=8 -XX:+PrintGCDetails NewSizeDemo



因为上面参数修改栈的大小=15m,eden/from=8,所以eden区空间>10m,所以就算循环分配10m的空间,下面也不会进行一次回收。



 



JVM常用参数及用法例子_JAVA_04

 



2.4 还可以通过-XX:NewRatio=n 来设置新生代/老年代 的比例。



2.5 当eden区大于当次分配内存(1M),并且from小于(1M)的话,新生代需要老年代做空间担保,1MB数组会进入老年代。



看完上面的参数设置过程,我们再来回顾下下面的图(好好回忆下):



 



JVM常用参数及用法例子_JAVA_05

 



 



3 堆溢出处理



为了记录堆溢出时的信息,可添加如下参数:



-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/xxx.dump



以上在发生堆溢出时,就会输出文件到xxx.dump,然后可用MAT分析(后面会讲)