JVM GC总结
参考 林昊 <分布式Java应用基础与实践>
1. 首先需要弄清JVM的内存结构,参考: 【转】JVM内存结构
2. JVM GC 大致可分为三类:Minor GC,Major GC和Full GC.
Minor GC指堆内存 新生代上发生的垃圾回收.
Major GC是指堆内存的旧生代 和 非堆内存的持久代 上发生的垃圾回收.
因为通常发生Major GC时至少要进行一次的Minor GC,
所以将这种Minor GC和Major GC同时发生的GC称为Full GC.
需要注意的是,并不是所有的Major都会导致Full GC.
(比如,在 ParallelScavenge 收集器的收集策略里,就有直接进行 Major GC 的策略选择过程)
通常可以任务发生Major GC时就是发生Full GC之时.
3 Minor GC 和 Major GC 都有几种不同的方式可选择.
3.1 新生代可用的GC(Minor Gc)
Minor GC 采用复制算法,将存活的对象从Eden和S0(或S1)拷贝到S1(或S0)上.
3.1.1 串行GC(Serial GC)
对象在从存活区(S0或S1)拷贝到旧生代之前经历的Minor次数由-XX:MaxTenuringThreshold控制
Eden 和 Survivor的空间大小受参数:-XX:SurvivorRatio控制.
SurvivorRatio = Eden 空间 / 一个Survivor的空间
比如新生代-Xmn10M,-XX:SurvivorRatio = 8,则Eden为8M,每个Survivor为1M.
通过配置JVM参数:-XX:PretenureSizeThreshold
使得对象大小超过这个数值时,对象直接在旧生代上分配空间.
Serial GC 在整个扫描和复制过程中都采用单线程的方式来进行,更加适用於单CPU,新生代空间较小,
以及对暂停时间要求不是非常高的应用.是client级别(CPU核数小于2或物理内存小于2GB)或32位
windows机器上默认的GC方式.
使用,-XX:+UseSerialGC参数强制使用Serial GC.
3.1.2 并行回收GC(Parallel Scavenge)
Eden S0 S1大小受InitialSurvivorRatio控制,JDK1.6之后也可以通过SurvivorRatio,但并行回收GC
将此值+2然后赋给InitialSurvivorRatio.
(1) InitialSurvivorRatio 和 SurvivorRatio都不设置
用-Xms20m -Xmx20m -Xmn10m -XX:+UseParallelGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC
执行,则Eden为7.5M,S0和S1 为1.25M,则7.5/1.25 = 6.
(2) 只配置SurvivorRatio = 10
用-Xms20m -Xmx20m -Xmn12m -XX:+UseParallelGC -XX:SurvivorRatio=10 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC
此时 Eden =10M,S0和S1 为1M,则10 / 1 = 10 等于设置的-XX:SurvivorRatio=10
(3) 只设置 InitialSurvivorRatio = 10
用-Xms20m -Xmx20m -Xmn10m -XX:+UseParallelGC -XX:InitialSurvivorRatio=10 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC
此时Eden =8M,S0和S1 为1M,8 / 1 = 8 = InitialSurvivorRatio - 2
(4) 同时设置SurvivorRatio = 10 和 InitialSurvivorRatio = 10
用-Xms20m -Xmx20m -Xmn10m -XX:+UseParallelGC -XX:SurvivorRatio=10 -XX:InitialSurvivorRatio=10 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC
因此,采用并行回收GC时:
如果没有配置SurvivorRatio和InitialSurvivorRatio,则默认值,Eden / Survivor = 6;
如果只配置了SurvivorRatio = 10则以这个为准Eden / Survivor = SurvivorRatio ;
如果只配置了InitialSurvivorRatio = 10 则 Eden / Survivor = InitialSurvivorRatio - 2;
如果同时配置了InitialSurvivorRatio 和 SurvivorRatio,则以InitialSurvivorRatio 为准,Eden / Survivor = InitialSurvivorRatio - 2
另外,使用并行回收GC时,虚拟机会根据运行情况动态调整Eden S0 和S1的大小,上面的值只是设置初始值,
可用通过使用-XX:-UseAdaptiveSizePolicy固定Eden S0和S1的大小为上面设置的值.
对于对象是否直接在旧生代上分配不受-XX:PretenureSizeThreshold控制,而是在Eden空间不够情况下,
当对象大小大于等于Eden大小一半时,即在旧生代上分配.
并行回收GC(Parallel Scavenge)也是采用复制算法,但是在扫描和复制是均采用多线程方式,且并行回收GC为大的
新生代回收做了很多优化.在多CPU机器上其回收的耗时比串行方式短,适用于多CPU,对暂停时间要求短的应用上.
并行回收GC是server级别(CPU核数超过2且物理内存超过2GB)的机器(32位window除外)上默认的GC方式.并行线程数量
在CPU核数小于等于8时,即为CPU核数,当CPU核数多于8时,计算公式为:3 + (CPU核数 * 5) / 8,也可通过
-XX:ParallelGCThreads = 4 来强制制定.
使用-XX:+UseParallelGC强制使用并行回收GC(Parallel Scavenge)
3.1.3并行GC(ParNew)
Eden 和S0 S1的空间分配方式和串行GC采用的方式相同.
并行GC方式必须与旧生代的CMS GC方式配合使用. CMS GC方式要求 Minor GC需采用并行方式并做一些特殊处理
(并行回收方式没有这种特殊处理),因此CMS GC只能和 并行GC(ParNew)一同使用.
同时,也是因为并行GC(ParNew)的特殊处理,是的Major GC的并行回收方式不能和ParNew GC方式同时使用.
使用-XX:+UsePaNewGC强制使用并行GC(ParNew)
3.2 旧生代和持久代可用的GC
JDK提供了串行,并行及并发三种GC来对就生代及持久代对象所占用的内存进行回收.
3.2.1 串行GC
串行基于Mark - Sweep - Compact实现,结合了Mark - Sweep, Mark - Compact做了一些改进.
过程:
(1) 从根集合对象扫描,按照三色着色啊法哪个是对对象进行标识;
(2) 遍历旧生代或持久代,找出未标记对象,并回收其内存;
(3) 执行活动压缩(Sliding Compaction)
串行执行过程中需要暂停应用.采用单线程方式,通常需要耗费较长时间,通过
-XX:+PrintGCApplicationStopTime来查看GC造成的暂停时间.
通过-XX:+UseSerialGC强制制定该方式.
3.2.1 并行GC
基于 Mark - Compact 实现.
过程:
(1) 将代空间分区域(区域个数和并行GC的线程数相同),然后使用多线程扫描标记着色对象,
同时更新其所在region的存活大小及位置.
(2) 确定压缩移动的region(通常旧生代左边存放的是一些活跃对象(不容易死的)
因此这部分对象所在的region通常不压缩)的region源和region目的地.
该过程目前为单线程进行.
(3) 基于(2)中的分析信息进行对象的移动和region的回收.
并行GC与之前的串行GC相比,大部分时候是多线程的,对应用造成的暂停时间会缩短.
但是由于旧生代较大,再扫描和标识对象上需要话费较长时间.
通过 -XX:+UseParallelGC 或 -XX:+UseParallelOldGC 来强制制定.
两者区别:
-XX:+UseParallelOldGC同时激活新生代并行垃圾回收和老年代的并行垃圾回收,
亦即,Minor GC和Full GC都是多线程的;
-XX:+UseParallelGC只会激活新生代的并行垃圾回收(旧生代使用的是Serial GC)。
也就是使用了-XX:+UseParallelOldGC会自动激活-XX:+UseParallelGC。
UseParallelGC would result in parallel young + serial old and
UseParallelOldGC in parrallel young + parralel old gcs.
参考:
use UseParallelOldGC instead of UseParallelGC #1105
Should we use UseParallelOldGC instead of UseParallelGC in hornetq user manual?:
3.2.3 并发(CMS Concurrent Mark-Sweep GC)
基于Mark-Sweep方式, 该方式可以减少GC应用暂停时间.
Mark-Sweep 可能会产生内存碎片.
并行 与 并发 区别在于,并行时 只有 垃圾回收线程运行,应用暂停了.
而并发 时 应用线程 和 垃圾回收线程可同时执行.
过程:
(1) 第一次标记,暂停应用,只标记存活的根对象(速度快,暂停时间短,因为根对象毕竟不太多)
(2) 并发标记 根据(1)的根对象,标记所有从根对象能够引用到的对象(耗时操作,并发进行,不停应用)
(3) 重新标记,暂停应用,重新标记在步骤(2)进行时可能出现的新的类似与(1)中的根对象
以及该根对象可达的所有存活对象,并对引用关系可能发生的变化做一些额外处理
(需要处理的对象也是少数,因而速度快,暂停时间短)
(4) 并发收集(耗时操作,并发进行,不停应用)
虽然有两次暂停,但是暂停时间都比较短,耗时长的都是并发执行的.
CMS方式的GC之后通常会产生内存碎片,因此CMS提供了内存碎片整理功能.
这个内存整理功能在没有使用CMS时也可以使用,可以通过
-XX:+UseCMSCompactAtFullCollection 在每次full gc之后都进行内存整理.
也可以指定-XX:+CMSFullGCsBeforeCompact=3来指定在若干次full gc之后
进行内存碎片整理.
使用:-XX:+UseComcMarkSweepGC来强制使用CMS 方式的GC,默认开启的线程数为:
(并行 GC线程数 + 3) / 4,可通过-XX:+ParallelCMSThreads=10来强制指定.
CMS GC的触发条件不是旧生代满了,而是当旧生代已用空间达到参数:
-XX:CMSInitiatingOccupancyFraction设置的百分比.比如,默认
-XX:CMSInitiatingOccupancyFraction=68%,则旧生代总工1000M,在已用空间达680M时
触发CMS GC.还有一种方式,是JVM自行触发,指JVM根据之前GC的频率及旧生代的增长趋势
来评估决定什么时候执行CMS GC,如果不希望JVM自行触发CMS GC,可以设置参数:
-XX:+UseCMSInitiatingOccupancyOnly=true设置.
可以通过设置参数-XX:+CMSPermGenSweepingEnabled使得持久代的GC也使用CMS.
持久代GC默认是使用Full GC.
4. GC触发条件
(1) 通常JVM在为对象分配空间是在新生代的Eden部分分配的.
当Eden的剩余空间已经不足以放下一个新对象时会触发Minor GC.
(2) 发生Minor GC时,Eden和S0(或S1)上的存活对象会被拷贝到S1(或S0)上.
当S1(或S0)的剩余空间不足以容纳要拷贝的对象时,对象被直接拷贝到
旧生代上;
当经历了若干次(具体的次数可以通过-XX:MaxTenuringThreshold参数配置,这里配置的是最大值,
也就是说,假如该值配置的5,则可能经历3次Minor GC后,对象就被拷贝到旧生代了,但最多不超过5次)
的Minor GC时,S1(或S0)上仍然存活的对象会被拷贝到旧生代上;
当Minor GC采用串行GC时,可以通过配置JVM参数:-XX:PretenureSizeThreshold
使得对象大小超过这个数值时,对象直接在旧生代上分配空间.
当Minor GC采用并行回收(Parallel Scavenge)GC,在Eden空间不够,在要分配空间的对象大小
超过Eden空间一半时,直接在旧生代上分配(不受-XX:PretenureSizeThreshold这个参数控制了).
(3) 当旧生代上空间不足以容纳要拷贝的对象时,会触发 Major GC.
CMS GC的触发条件不是旧生代满了,而是当旧生代已用空间达到参数:
-XX:CMSInitiatingOccupancyFraction设置的百分比.比如,默认
-XX:CMSInitiatingOccupancyFraction=68%,则旧生代总工1000M,在已用空间达680M时
触发CMS GC.还有一种方式,是JVM自行触发,指JVM根据之前GC的频率及旧生代的增长趋势
来评估决定什么时候执行CMS GC,如果不希望JVM自行触发CMS GC,可以设置参数:
-XX:+UseCMSInitiatingOccupancyOnly=true设置.
(4) 在持久代空间不足时也触发Full GC(比如Load一个class后导致持久代空间不足,或者反射调用).
可以通过设置参数-XX:+CMSPermGenSweepingEnabled,使用CMS收集持久代的类.
(5) Full Gc 触发情况
a. 代码中显示执行System.gc();
b. 旧生代空间不足
c. 持久代空间满了(没有设置-XX:+CMSPermGenSweepingEnabled)
c. CMS GC时出现promotion failed 和 concurrent mode failure
promotion failed是在执行Minor GC时,Survivor放不下,而此时旧生代也放不下时造成的
concurrent mode failure 是在执行CMS GC的过程中,同时有对象要放入旧生代,此时旧生代
空间不足造成的.
d. 统计得到Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间.
5. 示例代码
使用myeclipse测试代码,通过Run -> Open run dialogue 打开运行对话框,在
Arguments选项卡的vmarguments中设置JVM执行参数:
常用参数:
-Xms20m (堆内存最小空间)
-Xmx20m (堆内存最大空间)
-Xmn10m (堆内存 新生代空间)
-XX:SurvivorRatio=10(eden 和 Survivor空间大小比值,默认值8)
-XX:InitialSurvivorRatio=10(并行GC时用到)
-XX:+UseConcMarkSweepGC(使用CMS GC)
-verbose:gc
-XX:+PrintGCDetails (打印GC详细信息)
-XX:+PrintGC
-XX:+PrintGCTimeStamps (打印GC信息时打印相对时间)
-XX:+PrintGCDateStamps (打印GC信息时,打印详细日期时间)
-XX:+UseCMSCompactAtFullCollection (Full GC时使用GMS 整理内存碎片)
-XX:+PrintGCApplicationStoppedTime (打印GC时应用暂停时间)
-XX:+PrintGCApplicationConcurrentTime (GC之间运行了多少时间)
-Xloggc:D:/D/gc.log (将GC日志输出到文件,指定这个参数之后,控制台中不再打印GC日志了)
5.1 Minor GC触发示例:Eden 空间不足时触发Minor GC
package jvm;
/**
*
* 1. Eden 空间不足时触发Minor GC
* JVM参数:
* -Xms40m
* -Xmx40m
* -Xmn16m
* -XX:+UseParallelGC
* -verbose:gc
* -XX:+PrintGCDetails
* 此时Eden为12M,Survivor都是2M.
*
* 输出信息如下:
*
mino gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->1200K(38912K), 0.0086913 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
mino gc should happen
[GC [PSYoungGen: 12589K->1184K(14336K)] 12589K->1184K(38912K), 0.0043232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
PSYoungGen total 14336K, used 2453K [0x08200000, 0x09200000, 0x09200000)
eden space 12288K, 10% used [0x08200000,0x0833d780,0x08e00000)
from space 2048K, 57% used [0x09000000,0x09128050,0x09200000)
to space 2048K, 0% used [0x08e00000,0x08e00000,0x09000000)
PSOldGen total 24576K, used 0K [0x06a00000, 0x08200000, 0x08200000)
object space 24576K, 0% used [0x06a00000,0x06a00000,0x08200000)
PSPermGen total 12288K, used 2087K [0x02a00000, 0x03600000, 0x06a00000)
object space 12288K, 16% used [0x02a00000,0x02c09c10,0x03600000)
*
*使用 jstat工具查看可以看到YGC 发生了2次,耗时分别为19毫秒和26毫秒.
*
>jstat -gcutil 110788 2000
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 87.90 22.17 0.00 46.22 1 0.019 0 0.000 0.019
0.00 87.90 30.51 0.00 46.22 1 0.019 0 0.000 0.019
0.00 87.90 40.88 0.00 46.23 1 0.019 0 0.000 0.019
0.00 87.90 49.21 0.00 46.23 1 0.019 0 0.000 0.019
0.00 87.90 58.57 0.00 46.26 1 0.019 0 0.000 0.019
0.00 87.90 58.57 0.00 46.26 1 0.019 0 0.000 0.019
0.00 87.90 59.59 0.00 46.26 1 0.019 0 0.000 0.019
0.00 87.90 59.59 0.00 46.26 1 0.019 0 0.000 0.019
0.00 87.90 60.61 0.00 46.27 1 0.019 0 0.000 0.019
0.00 87.90 60.61 0.00 46.27 1 0.019 0 0.000 0.019
0.00 87.90 62.65 0.00 46.32 1 0.019 0 0.000 0.019
0.00 87.90 62.65 0.00 46.32 1 0.019 0 0.000 0.019
0.00 87.90 63.67 0.00 46.35 1 0.019 0 0.000 0.019
0.00 87.90 63.67 0.00 46.36 1 0.019 0 0.000 0.019
0.00 87.90 64.69 0.00 46.38 1 0.019 0 0.000 0.019
0.00 87.90 73.03 0.00 46.38 1 0.019 0 0.000 0.019
0.00 87.90 74.05 0.00 46.40 1 0.019 0 0.000 0.019
0.00 87.90 82.38 0.00 46.40 1 0.019 0 0.000 0.019
0.00 87.90 92.76 0.00 46.43 1 0.019 0 0.000 0.019
87.12 0.00 8.33 0.00 46.43 2 0.026 0 0.000 0.026
87.12 0.00 20.70 0.00 46.48 2 0.026 0 0.000 0.026
87.12 0.00 29.03 0.00 46.48 2 0.026 0 0.000 0.026
87.12 0.00 38.19 0.00 46.53 2 0.026 0 0.000 0.026
87.12 0.00 46.52 0.00 46.53 2 0.026 0 0.000 0.026
87.12 0.00 56.50 0.00 46.61 2 0.026 0 0.000 0.026
87.12 0.00 64.84 0.00 46.61 2 0.026 0 0.000 0.026
87.12 0.00 74.82 0.00 46.70 2 0.026 0 0.000 0.026
87.12 0.00 74.82 0.00 46.70 2 0.026 0 0.000 0.026
87.12 0.00 79.29 0.00 46.80 2 0.026 0 0.000 0.026
87.12 0.00 79.29 0.00 46.80 2 0.026 0 0.000 0.026
87.12 0.00 80.04 0.00 46.80 2 0.026 0 0.000 0.026
87.12 0.00 80.04 0.00 46.80 2 0.026 0 0.000 0.026
87.12 0.00 81.55 0.00 46.81 2 0.026 0 0.000 0.026
87.12 0.00 81.55 0.00 46.81 2 0.026 0 0.000 0.026
87.12 0.00 82.32 0.00 46.81 2 0.026 0 0.000 0.026
87.12 0.00 82.32 0.00 46.81 2 0.026 0 0.000 0.026
87.12 0.00 83.84 0.00 46.81 2 0.026 0 0.000 0.026
87.12 0.00 92.18 0.00 46.81 2 0.026 0 0.000 0.026
87.12 0.00 92.93 0.00 46.82 2 0.026 0 0.000 0.026
*/
public class MinorGCDemo
{
private static void happenMinorGC(int happenMinorGCIndex) throws Exception
{
for(int i=0;i<happenMinorGCIndex;i++)
{
if(i==happenMinorGCIndex - 1)
{
Thread.sleep(20000);
System.out.println("minor gc should happen");
}
new MemoryObject(1024 * 1024);
Thread.sleep(2000);
}
}
public static void main(String[] args) throws Exception
{
MemoryObject object = new MemoryObject(1024 * 1024);//占用1M空间的对象
for(int i=0;i<2;i++)
{
happenMinorGC(11);
//第一次分配了11个1M 加上之前分配的1M在分配第11个时,
//达到eden的最大空间12M,输出minor gc should happen
//后进行Minor GC
Thread.sleep(2000);
}
}
}
class MemoryObject
{
private byte[] bytes;
public MemoryObject(int objectSize)
{
this.bytes = new byte[objectSize];
}
}
5.2 Minor Gc时,survivor 空间不足,对象直接进入旧生代.
package jvm;
/**
*
* 2. Minor Gc时,survivor 空间不足,对象直接进入旧生代.
*
* JVM参数:
* -Xms40m
* -Xmx40m
* -Xmn16m
* -XX:+UseParallelGC
* -verbose:gc
* -XX:+PrintGCDetails
*运行结果如下,其中PSOldGen total 24576K, used 2048K [0x06a00000, 0x08200000, 0x08200000) 说明旧生代已占有2M空间
*minor gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->3248K(38912K), 0.0115163 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
Heap
PSYoungGen total 14336K, used 2469K [0x08200000, 0x09200000, 0x09200000)
eden space 12288K, 10% used [0x08200000,0x0833d780,0x08e00000)
from space 2048K, 58% used [0x08e00000,0x08f2c050,0x09000000)
to space 2048K, 0% used [0x09000000,0x09000000,0x09200000)
PSOldGen total 24576K, used 2048K [0x06a00000, 0x08200000, 0x08200000)
object space 24576K, 8% used [0x06a00000,0x06c00010,0x08200000)
PSPermGen total 12288K, used 2087K [0x02a00000, 0x03600000, 0x06a00000)
object space 12288K, 16% used [0x02a00000,0x02c09c48,0x03600000)
jstat输出为:
C:\Documents and Settings\10106511>jstat -gcutil 108148 2000
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 90.04 0.00 46.21 0 0.000 0 0.000 0.000
0.00 0.00 98.38 0.00 46.21 0 0.000 0 0.000 0.000
0.00 0.00 98.38 0.00 46.24 0 0.000 0 0.000 0.000
0.00 0.00 98.38 0.00 46.24 0 0.000 0 0.000 0.000
0.00 89.07 12.62 8.33 46.26 1 0.015 0 0.000 0.015
0.00 89.07 12.62 8.33 46.26 1 0.015 0 0.000 0.015
0.00 89.07 23.24 8.33 46.28 1 0.015 0 0.000 0.015
0.00 89.07 23.24 8.33 46.28 1 0.015 0 0.000 0.015
0.00 89.07 24.51 8.33 46.32 1 0.015 0 0.000 0.015
可以看到进行了一次Minor(YGC由0到1后) O字段从0到8.33%,表对象被复制到旧生代了.
*/
public class MinorSurvivorDemo
{
private static void happenMinorGC(int happenMinorGCIndex) throws Exception
{
for(int i=0;i<happenMinorGCIndex;i++)
{
if(i==happenMinorGCIndex - 1)
{
Thread.sleep(2000);
System.out.println("minor gc should happen");
}
new MemoryObject(1024 * 1024);
}
}
public static void main(String[] args) throws Exception
{
MemoryObject object = new MemoryObject(1024 * 1024);//1M
MemoryObject object2 = new MemoryObject(1024 * 1024 * 2);//2M
happenMinorGC(9);
//分配到第九个对象时,Eden满了(12M),导致GC,复制对象到Survivor时,先复制1M的(达到Survivor的空间了),
//导致Survivor满了,然后将2M对象复制到旧生代.
Thread.sleep(2000);
}
}
5.3 测试使用不同GC方式时,输出的GC日志格式不同
package jvm;
/**
*
* 测试使用不同GC方式时,输出的GC日志格式不同
*
* 1. 使用串行GC -XX:+UseSerialGC
* vm参数如下:
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseSerialGC
-XX:SurvivorRatio=6
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
* 此时Eden为12M,Survivor都是2M.
*输出信息:
*minor gc should happen
[GC [DefNew: 11509K->1173K(14336K), 0.0045310 secs] 11509K->1173K(38912K), 0.0045777 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
...
表示 使用-XX:+UseSerialGC时,GC日志中前缀使用的是DefNew
[DefNew: 11509K->1173K(14336K), 0.0045310 secs] 表示 Minor GC使得新生代已用空间从11509K变成1173K,可用空间14336
11509K->1173K(38912K) 表示GC使得堆空间的已用空间从11509K变成1173K,总可用空间为(38912K)
0.0045777 secs 表示本次GC总耗时.
[Times: user=0.00 sys=0.00, real=0.00 secs] 表示GC时CPU耗时占 CPU user和sys的百分比,以及总耗时
2.使用并行回收GC -XX:+UseParallelGC
* vm参数如下:
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseParallelGC
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
输出:
minor gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->3248K(38912K), 0.0049179 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
.....
3.使用并行GC -XX:+UseParNewGC
* vm参数如下:
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseParNewGC
-XX:SurvivorRatio=6
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
输出为:
minor gc should happen
[GC [DefNew: 11509K->1173K(14336K), 0.0034538 secs] 11509K->1173K(38912K), 0.0035021 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
...
由 DefNew 可知,使用-XX:+UseParNewGC时,Minor GC使用的是串行方式
4. 使用并行GC -XX:+UseParallelOldGC
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseParallelOldGC
-XX:SurvivorRatio=6
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
输出:
minor gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->1200K(38912K), 0.0029191 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
...
说明使用-XX:+UseParallelOldGC时,Minor GC使用的是并行回收GC -XX:+UseParallelGC
5. 单独使用 -XX:+UseConcMarkSweepGC(Major GC方式)
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseConcMarkSweepGC
-XX:SurvivorRatio=6
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
输出为:
minor gc should happen
[GC [DefNew: 11509K->1173K(14336K), 0.0046844 secs] 11509K->1173K(38912K), 0.0047808 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
...
说明 Minor GC使用的是串行GC,-XX:+UseSerialGC,即,单独配置-XX:+UseConcMarkSweepGC时,
默认-XX:+UseConcMarkSweepGC和-XX:+UseSerialGC配合使用
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC 只有这种组合是合法的,也可以省略-XX:+UseParNewGC
下面组合都不行
-XX:+UseConcMarkSweepGC -XX:+UseParallelOldGC
-XX:+UseConcMarkSweepGC -XX:+UseParallelGC
-XX:+UseConcMarkSweepGC -XX:+UseSerialGC
*/
public class MutilGCLog
{
private static void happenMinorGC(int happenMinorGCIndex) throws Exception
{
for(int i=0;i<happenMinorGCIndex;i++)
{
if(i==happenMinorGCIndex - 1)
{
Thread.sleep(2000);
System.out.println("minor gc should happen");
new MemoryObject(1024 * 1024 * 3);
}
new MemoryObject(1024 * 1024);
//Thread.sleep(5000);
}
}
public static void main(String[] args) throws Exception
{
MemoryObject object = new MemoryObject(1024 * 1024);
happenMinorGC(11);
Thread.sleep(2000);
}
}