常用的JVM配置参数

常用JVM配置参数

大纲:

n  Trace(轨迹/痕迹)跟踪参数

n  堆的分配参数

n  栈的分配参数

Trace跟踪参数

-verbose:gc

java -verbose:gc 中参数-verbose:gc 表示输出虚拟机中GC的详细情况.

使用后输出如下:

[Full GC 168K->97K(1984K), 0.0253873 secs]

解读如下:

箭头前后的数据168K97K分别表示垃圾收集GC前后所有存活对象使用的内存容量,说明168K-97K=71K的对象容量被回收,括号内的数据1984K为堆内存的总容量收集所需要的时间是0.0253873(这个时间在每次执行的时候会有所不同)

-XX:+printGC

可以打印GC的简要信息

–      [GC 4790K->374K(15872K), 0.0001606 secs]

–      4790KGC前堆被使用的容量

扫描二维码关注公众号,回复: 1338408 查看本文章

–      374KGC后堆被使用的容量

–      15872K:堆的总容量

–      0.0001606 secs:本次GC垃圾收集花费的时间

–      [GC 4790K->374K(15872K), 0.0001474 secs]

–      [GC 4790K->374K(15872K), 0.0001563 secs]

–      [GC 4790K->374K(15872K), 0.0001682 secs]

参数配置和理解

1:参数分类和说明

jvm参数分固定参数和非固定参数

1):固定参数

如:-Xmx,-Xms,-Xmn,-Xss.

2):非固定参数

如:

-XX:+<option> 启用选项

-XX:-<option> 不启用选项

-XX:<option>=<number> 给选项设置一个数字类型值,可跟单位,例如 128k, 2g

-XX:<option>=<string> 给选项设置一个字符串值,例如-XX:HeapDumpPath=./dump.log

-XX:+PrintGCDetails

n  -XX:+PrintGCDetails

–      打印GC详细信息

–      只要设置-XX:+PrintGCDetails 就会自动带上-verbose:gc和-XX:+PrintGC

–      在程序结束后,会把整个程序的堆的基本状况打印出来。

-XX:+PrintGCTimeStamps

n  -XX:+PrintGCTimeStamps

–      打印CG发生的时间戳

n  例GC发生的时间戳

–      [GC[DefNew: 4416K->0K(4928K), 0.0001897 secs] 4790K->374K(15872K), 0.0002232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

–      DefNew:说明这是一个新生代的GC信息

–      4416KGC之前,新生代被使用的内存大小

–      0KGC之后,新生代被使用的内存大小

–      4928K:新生代的总内存大小

–      0.0001897 secs:新生代GC垃圾收集花费的时间

–      4790KGC之前堆中总共被使用的内存大小

–      374KGC之后堆中总共被使用的内存大小

–      15872K:堆的内存总大小

–      0.0002232 secs:整个堆GC垃圾收集所花费的时间

–      Times:

–      user=0.00:用户耗时

–      sys=0.00:系统耗时

–      real=0.00:实际耗时

s

n  -XX:+PrintGCDetails在程序结束后的输出

–      Heap[z1] 

–       def new generation[z2]    total[z3]  13824K[z4] , used [z5] 11223K [0x27e80000[z6] (低边界), 0x28d80000[z7] (当前边界), 0x28d80000[z8] (最高边界)[z9] )

–        eden space[z10]  12288K[z11] ,  91% used [0x27e80000, 0x28975f20, 0x28a80000)

–        from space[z12]  1536K,   0% used [0x28a80000, 0x28a80000, 0x28c00000)

–        to   space[z13]  1536K,   0% used [0x28c00000, 0x28c00000, 0x28d80000)

–       tenured generation[z14]    total 5120K, used 0K [0x28d80000, 0x29280000, 0x34680000)

–         the space 5120K,   0% used [0x28d80000, 0x28d80000, 0x28d80200, 0x29280000)

–       compacting perm gen[z15]   total 12288K, used 142K [0x34680000, 0x35280000, 0x38680000)

–         the space 12288K,   1% used [0x34680000, 0x346a3a90, 0x346a3c00, 0x35280000)

–          ro space[z16]  10240K,  44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)

–          rw space[z17]  12288K,  52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000)

 

-Xloggc:log/gc.log

n  -Xloggc:log/gc.log(意为:将GC日志信息输出到系统当前位置的log目录下的gc.log文件)

–      指定GC log日志的输出的位置,以文件输出(一般情况下,GC的日志输出都是在控制台的)

–      帮助开发人员分析问题

-XX:+PrintHeapAtGC

n  -XX:+PrintHeapAtGC

–      每次一次GC的前后,都打印堆信息

{Heap before GC invocations=0[z18]  (full 0)://GC前,堆内存的使用情况

 def new generation   total 3072K, used 2752K [0x33c80000, 0x33fd0000, 0x33fd0000)

  eden space 2752K, 100% used [0x33c80000, 0x33f30000, 0x33f30000)

  from space 320K,   0% used [0x33f30000, 0x33f30000, 0x33f80000)

  to   space 320K,   0% used [0x33f80000, 0x33f80000, 0x33fd0000)

 tenured generation   total 6848K, used 0K [0x33fd0000, 0x34680000, 0x34680000)

   the space 6848K,   0% used [0x33fd0000, 0x33fd0000, 0x33fd0200, 0x34680000)

 compacting perm gen  total 12288K, used 143K [0x34680000, 0x35280000, 0x38680000)

   the space 12288K,   1% used [0x34680000, 0x346a3c58, 0x346a3e00, 0x35280000)

    ro space 10240K,  44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)

    rw space 12288K,  52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000)

[GC[DefNew: 2752K->320K(3072K), 0.0014296 secs] 2752K->377K(9920K), 0.0014604 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [z19] 

Heap after GC invocations=1[z20]  (full 0)://GC之后,对内存的使用情况

 def new generation   total 3072K, used 320K [0x33c80000, 0x33fd0000, 0x33fd0000)

  eden space 2752K,   0% used [0x33c80000, 0x33c80000, 0x33f30000)

  from space 320K, 100% used [0x33f80000, 0x33fd0000, 0x33fd0000)

  to   space 320K,   0% used [0x33f30000, 0x33f30000, 0x33f80000)

 tenured generation   total 6848K, used 57K [0x33fd0000, 0x34680000, 0x34680000)

   the space 6848K,   0% used [0x33fd0000, 0x33fde458, 0x33fde600, 0x34680000)

 compacting perm gen  total 12288K, used 143K [0x34680000, 0x35280000, 0x38680000)

   the space 12288K,   1% used [0x34680000, 0x346a3c58, 0x346a3e00, 0x35280000)

    ro space 10240K,  44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)

    rw space 12288K,  52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000)

}

-XX:+TraceClassLoading

n  -XX:+TraceClassLoading

–      监控类的加载,查看哪些类被加载到了虚拟机

•       [Loaded java.lang.Object from shared objects file]

•       [Loaded java.io.Serializable from shared objects file]

•       [Loaded java.lang.Comparable from shared objects file]

•       [Loaded java.lang.CharSequence from shared objects file]

•       [Loaded java.lang.String from shared objects file]

•       [Loaded java.lang.reflect.GenericDeclaration from shared objects file]

•       [Loaded java.lang.reflect.Type from shared objects file]

-XX:+PrintClassHistogram

n  -XX:+PrintClassHistogram

–      按下Ctrl+Break[z21] 后,打印类的信息

num     #instances         #bytes  class name

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

   1:        890617      470266000  [B

   2:        890643       21375432  java.util.HashMap$Node

   3:        890608       14249728  java.lang.Long

   4:            13        8389712  [Ljava.util.HashMap$Node;

   5:          2062         371680  [C

   6:           463          41904  java.lang.Class

–      分别显示:序号、实例数量、总大小、类型

堆的分配参数

-Xmx –Xms

n  -Xmx –Xms

–      指定最大堆和最小堆

–      -Xmx:最大堆,堆最大可以分配扩展到多大的空间。

–      -Xms:最小堆,堆最小占用多少空间,系统启动时给堆初始分配多少空间。

n  -Xmx20m -Xms5m  运行代码:

–      System.out.print("Xmx=");

–      System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");//打印最大可扩展内存

–      System.out.print("free mem=");

–      System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");//打印可使用的空闲内存

–      System.out.print("total mem=");

–      System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");//打印已分配的总内存

打印输出:Xmx=19.375M

free mem=4.342750549316406M

total mem=4.875M

n  -Xmx20m -Xms5m  运行代码

–      byte[] b=new byte[1*1024*1024];

–      System.out.println("分配了1M空间给数组");

–      System.out.print("Xmx=");

–      System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");

–      System.out.print("free mem=");

–      System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");

–      System.out.print("total mem=");

–      System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");

打印输出:分配了1M空间给数组

Xmx=19.375M

free mem=3.4791183471679688M

total mem=4.875M

Java会尽可能维持在最小堆

n  -Xmx20m -Xms5m  运行代码

n  b=new byte[4*1024*1024];

n  System.out.println("分配了4M空间给数组");

n  System.out.print("Xmx=");

n  System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");

n  System.out.print("free mem=");

n  System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");

n  System.out.print("total mem=");

n  System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");

打印输出:分配了4M空间给数组

Xmx=19.375M

free mem=3.5899810791015625M

total mem=9.00390625M(分配的总内存变多了

n  -Xmx20m -Xms5m  运行代码

n  System.gc();

n  System.out.println("回收内存");

n  System.out.print("Xmx=");

n  System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");

n  System.out.print("free mem=");

n  System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");

n  System.out.print("total mem=");

n  System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");

打印输出:回收内存

Xmx=19.375M

free mem=6.354591369628906M(空闲内存增多了

total mem=10.75390625M

-Xmx 和 –Xms 应该保持一个什么关系,可以让系统的性能尽可能的好呢?

-Xmn

n  -Xmn

–      设置新生代大小

-XX:NewRatio

n  -XX:NewRatio

–      新生代(eden+2*s)和老年代(不包含永久区)的比值

–      如果设置为4(-XX:NewRatio=4) ,表示 新生代:老年代=1:4,即年轻代占堆的1/5

-XX:SurvivorRatio

n  -XX:SurvivorRatio

–      设置两个Survivor(幸存)区和eden(伊甸区)的比

–      如果设置为8(-XX:SurvivorRatio=8),表示 两个Survivor :eden=2:8,即一个Survivor占年轻代的1/10

示例:

-Xmx20m -Xms20m -Xmn1m  -XX:+PrintGCDetails

代码:

public static void main(String[] args) {

   byte[] b=null;

   for(int i=0;i<10;i++)

       b=new byte[1*1024*1024];

}

运行参数:

-Xmx20m -Xms20m -Xmn1m  -XX:+PrintGCDetails

日志打印:

结果分析

  1. 没有触发GC
  2. 全部分配在老年代

-Xmx20m -Xms20m -Xmn15m  -XX:+PrintGCDetails

代码:

public static void main(String[] args) {

   byte[] b=null;

   for(int i=0;i<10;i++)

       b=new byte[1*1024*1024];

}

运行参数:

-Xmx20m -Xms20m -Xmn15m  -XX:+PrintGCDetails

日志打印:

实际占用空间大约10M 因为有系统级别的对象 如ClassLoader Thread等

结果分析:

  1. 没有触发GC
  2. 全部分配在eden
  3. 老年代没有使用

-Xmx20m -Xms20m –Xmn7m  -XX:+PrintGCDetails

代码:

public static void main(String[] args) {

   byte[] b=null;

   for(int i=0;i<10;i++)

       b=new byte[1*1024*1024];

}

运行参数:

-Xmx20m -Xms20m -Xmn7m  -XX:+PrintGCDetails

日志打印:

一共回收7M 剩余3M

S0 s1 太小无法周转

结果分析:

1.进行了2次新生代GC

2.s0 s1 太小需要老年代担保

-Xmx20m -Xms20m -Xmn7m   -XX:SurvivorRatio=2 -XX:+PrintGCDetails

代码:

public static void main(String[] args) {

   byte[] b=null;

   for(int i=0;i<10;i++)

       b=new byte[1*1024*1024];

}

运行参数:

-Xmx20m -Xms20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails

日志打印:

回收7M 剩余3M

结果分析:

1.进行了3次新生代GC

2.s0(from) s1(to) 增大

-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:+PrintGCDetails

代码:

public static void main(String[] args) {

   byte[] b=null;

   for(int i=0;i<10;i++)

       b=new byte[1*1024*1024];

}

运行参数:

-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:+PrintGCDetails

日志打印:

结果分析:

比例分配,新生代 老年代对半开

对象全部留在新生代

-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=3 -XX:+PrintGCDetails

代码:

public static void main(String[] args) {

   byte[] b=null;

   for(int i=0;i<10;i++)

       b=new byte[1*1024*1024];

}

运行参数:

-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=3 -XX:+PrintGCDetails

日志打印:

结果分析:

减少了s0(from) s1(to) GC数量变少,老年代未使用 空间使用率更高

-XX:+HeapDumpOnOutOfMemoryError

n  -XX:+HeapDumpOnOutOfMemoryError

–      发生OOM异常时导出堆到文件

-XX:+HeapDumpPath

n  -XX:+HeapDumpPath

–      发生OOM异常时,导出的堆放到文件的文件路径

示例:

-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

运行参数:

-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

代码及运行结果:

Vector v=new Vector();

for(int i=0;i<25;i++)

v.add(new byte[1*1024*1024]);

查看导出的堆文件:

-XX:OnOutOfMemoryError

n  -XX:OnOutOfMemoryError

–      在发生OOM异常时,执行一个脚本

–      参数示例:"-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p[z22] ”

–      printstack.bat 的内容:D:/tools/jdk1.7_40/bin/jstack -F %1 > D:/a.txt

–      当程序OOM时,在D:/a.txt中将会生成线程的dump

–      也可以在OOM时,发送邮件,甚至是重启程序,主要看脚本怎么写。

堆的分配参数 – 总结

n  根据实际事情调整新生代和幸存代的大小

官方推荐新生代占堆的3/8

幸存代占新生代的1/10

n  在OOM时,记得Dump出堆,确保可以排查现场问题

永久区分配参数

-XX:PermSize  -XX:MaxPermSize

n  -XX:PermSize  -XX:MaxPermSize

–      设置永久区的初始空间和最大空间

–      他们表示,一个系统可以容纳多少个类型(即可以加载多少个.class文件)

示例:

n  使用CGLIB等库的时候,可能会产生大量的类,这些类,有可能撑爆永久区导致OOM异常

代码:

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

    CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap());//不断产生新的类

}

查看日志:

分析导致OOM异常的原因

n  打开堆的Dump(导出文件)

–      堆空间实际占用非常少

–      但是永久区溢出 一样抛出OOM

如果堆空间没有用完也抛出了OOM,有可能是永久区导致的

栈大小分配

-Xss

-Xss

–      通常只有几百K

–      决定了函数调用的深度

–      每个线程都有独立的栈空间

–      局部变量、方法参数 分配在栈上

示例:

代码:

public class TestStackDeep {

       private static int count=0;

       public static void recursion(long a,long b,long c){

              long e=1,f=2,g=3,h=4,i=5,k=6,q=7,x=8,y=9,z=10;

              count++;

              recursion(a,b,c);//递归调用

       }

       public static void main(String args[]){

              try{

                     recursion(0L,0L,0L);

              }catch(Throwable e){

                     System.out.println("deep of calling = "+count);

                     e.printStackTrace();

              }

       }

}

运行参数:

-Xss128K

输出结果:

deep of calling = 701

java.lang.StackOverflowError

运行参数:

-Xss256K

输出结果:

deep of calling = 1817

java.lang.StackOverflowError

经验总结:

栈空间越大,调用层次越深,去掉局部变量 调用层次可以更深

 [z1]

 [z2]新生代的内存状况

 [z3]总共可用空间

 [z4]12288K+ 1536K

 [z5]已经使用的空间

 [z6]该区间在内存中的起始位置

 [z7]该区间当前已经分配的内存所到的位置。

 [z8]该区间最高可以申请到的内存的位置。就目前的情况来看,新生代的当前边界等于最高边界,表示新生代的内存已经分配完了,不能再做扩展了。

 [z9](0x28d80000-0x27e80000)

/1024/1024=15M

 [z10]伊甸园区,对象出生的地方

 [z11]总共可用的空间

 [z12]GC复制算法,幸存代from区

 [z13]GC复制算法,幸存代to区,他和from区的总内存大小一定是相等的。这两块区域是用于GC收集的复制算法的。这两块区域,只有一块是可用的,另一块是为复制算法准备的。互为备用,每次GC之后,相互切换角色。

 [z14]老年代的内存的总体状况

 [z15]永久区(方法区)的内存状况。Jdk5.0之后,会有一个共享区间,一些基础的java类会被加载到这个共享区间,供所有的jvm虚拟机使用。所以这里方法区被占用的空间不大。只有142k。

 [z16]只读共享区间内存情况

 [z17]可读可写共享区间内存情况。一些基础类主要是加载到了这两个共享区间,所以它们内存被使用率比较高。

 [z18]调用0次GC的时候

 [z19]GC的情况

 [z20]调用1次GC的时候

 [z21]老键盘在ESC行最右边,新键盘在方向键那块右上角,多媒体键盘和笔记本可能没有。用ctrl+c或

Esc替代。

 [z22]%p代表的是当前这个java程序的pid,也就是进程id

猜你喜欢

转载自my.oschina.net/u/3512041/blog/1822637