针对JVM堆的设置一般,可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,我们通常把最大、最小设置为相同的值。
年轻代和年老代将根据默认的比例(1:2)分配堆内存,可以通过调整二者之间的比率NewRadio来调整二者之间的大小,也可以针对回收代,比如年轻代,通过-XX:newSize -XX:MaxNewSize来设置其绝对大小。同样,为了防止年轻代的堆收缩,我们通常会把-XX:newSize-XX:MaxNewSize设置为同样大小。
PS:使用-XX:+UseConcMarkSweepGC设置年老代为并发收集的情况下-XX:NewRatio参数失效,并且原因不明。所以,此时年轻代大小最好用-Xmn设置。
Ø 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
Ø 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
Ø 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:
ü 并发垃圾收集信息
ü 持久代并发收集次数
ü 传统GC信息
ü 花在年轻代和年老代回收上的时间比例减少年轻代和年老代花费的时间,一般会提高应用的效率
Ø 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
年轻代与年老代之间的比例应该如何设置才算合理?这毫无疑问时一个没问答案的问题。需要根据实际情况的不同进行设置。根据测试结果基本可以得出以下规律:
Ø 更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC
Ø 更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率
Ø 如何选择应该依赖应用程序对象生命周期的分布情况:如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性,在抉择时应该根据以下两点:(A)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理 (B)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间。
Ø 在配置较好的机器上(比如多核、大内存),可以为年老代选择并行收集算法:-XX:+UseParallelOldGC ,默认为Serial收集
Ø 线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用。理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统。
根据测试性能对比,不同的年轻代和年老代比例对性能有不同影响。服务器测试结果显示在堆空间为8GB的情况下,年轻代占2GB,年老代占6GB的,并且使用并发GC算法,WebLogic性能最优。
因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:
1. -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
2. -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用(一般设置为128K或者256K)。理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统。
GC算法的组合基本情况如下:
|
新生代GC方式 |
年老代和持久代GC方式 |
-XX:+UseSerialGC |
串行GC |
串行GC |
-XX:+UseParallelGC |
并行回收GC |
Parallel Mark Sweep GC |
-XX:+UseConcMarkSweepGC |
并行GC |
并发GC 当出现concurrent mode failure时采用串行GC |
-XX:+UseParNewGC |
并行GC |
串行GC |
-XX:+UseParallelOldGC |
并行回收GC |
Parallel Compacting GC |
-XX:+UseConcMarkSweepGC -XX:-UseParNewGC |
串行GC |
并发GC 当出现Concurrent Mode Failure或者Promotion Failed时采用串行GC |
不支持的组合方式 |
1.-XX:+UseParNewGC –XX:+UseParallelOldGC 2.-XX:UseParNewGC –XX:+UseSerialGC |
堆空间分配不合理,或者GC算法选择不合理都可能会导致频繁Full GC。发生Full GC时首先看堆空间分配,可以先扩大堆空间,在进行测试。在堆空间分配比较合理的情况再进行GC算法测试。
垃圾回收统计信息参数主要有:
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
主流工具可以选择:Jconsole,jProfile,VisualVM
Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪。
JProfiler:商业软件,需要付费。功能强大。
VisualVM:JDK自带,功能强大,与JProfiler类似。推荐使用,使用方法详见官方文档
http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/jmx_connections.html
观察内存释放情况、CPU利用率、GC信息
在配置时可以选择GC相关的参数输出GC的信息