目录
垃圾收集器有串行收集器,比如 Serial收集器+Serial Old收集器,Parallel Scavenge+Parallel Old收集器等等。该如何让这些不同的垃圾收集器组合触发使用呢?
-XX:+UseParallelGC
在1.8版本的JDK运行时,JVM默认采用此种垃圾收集器组合来进行垃圾回收。可以通过+PrintCommandLineFlags
参数查看JVM运行默认设置的JVM参数信息。
JVM设置-XX:+UseParallelGC
参数,即采用此种垃圾收集器进行垃圾回收。在JDK 1.8.0_291版本默认使用此种收集策略。
收集器垃圾回收日志格式如下:
其中,PSYongGen
和ParOldGen
就印证了使用Parallel Scavenge+Parallel Old收集器进行垃圾回收。
-XX:+UseSerialGC
设置该参数后,JVM使用Serial+Serial Old收集器进行垃圾回收,DefNew和Tenured分别与之对应。
-XX:+UseParNewGC
设置该参数后, JVM使用ParNew+Serial Old收集器进行垃圾回收。
JVM有明确提示,不建议这么设置:
Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release
-XX:+UseConcMarkSweepGC
老年代使用CMS收集器。
-XX:PretenureSizeThreshold
-XX:PretenureSizeThreshold 设置对象超过多大值时直接在老年代分配。需要显示指定垃圾回收器类型,否则不会生效。
示例配置:
-verbose:gc
-Xmn10M
-Xms20M
-Xmx20M
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:PretenureSizeThreshold=4194304
-XX:+UseSerialGC
-XX:MaxTenuringThreshold
该参数主要是控制新生代需要经历多少次GC晋升到老年代中的最大阈值。
该参数默认值15,CMS默认值6,G1默认值15(在JVM中,该数值由4个bit表示,最大值为1111,即15)
但并非意味着,对象必须要经历15次YGC才会晋升到老年代中。例如,当survivor区空间不够时,便会提前进入到老年代中,但这个次数一定不大于设置的最大阈值。
-XX:TargetSurvivorRatio
一个计算期望s区存活大小(Desired survivor size)的参数。默认值为50,即50%。
当一个S区中所有的age对象的大小如果大于等于Desired survivor size,则重新计算threshold,以age和MaxTenuringThreshold两者的最小值为准, 即
newThreshold = min(age, MaxTenuringThreshold);
如下代码能更好地理解MaxTenuringThreshold与TargetSurvivorRatio这两个参数:
/**
* #### -XX:MaxTenuringThreshold
* <p>
* 在可以自动调节对象晋升到老年代阈值的GC中,设置该阈值的最大值。
* <p>
* 该参数默认值15,CMS默认值6,G1默认值15(在JVM中,该数值由4个bit表示,最大值为1111,即15)
* <p>
* 晋升到老年代的对象的年龄。每个对象在坚持过一次Minor GC后,年龄就+1。
*
*
* 当一个S区中所有的age对象的大小如果大于等于Desired survivor size
* 则重新计算threshold,以age和MaxTenuringThreshold两者的最小值为准
*/
/*
-verbose:gc
-Xmx200m //最大堆空间大小为200M
-Xmn50m //新生代大小50M
-XX:TargetSurvivorRatio=60 //当Survivor空间已使用60%,则重新计算对象晋升的阈值, 不会在使用MaxTenuringThreshold的值
-XX:+PrintTenuringDistribution // 打印对象在survivor空间的年龄情况,有多少对象的age是多少
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=4 //对象在新生代存活年龄的最大值的阈值
-XX:+PrintGCDateStamps //打印gc的时间戳
-XX:+UseParNewGC // 针对新生代的垃圾收集器
-XX:+UseConcMarkSweepGC //针对老年代,使用CMS收集器
*/
public class MyTest3 {
public static void main(String[] args) throws InterruptedException {
// 新生代大小50M,Eden40M,Survivor区5M
// 总共1M,在该方法执行完之前,不会被回收
byte[] byte_1 = new byte[512 * 1024];
byte[] byte_2 = new byte[512 * 1024];
// 执行后,存在对象分配和垃圾回收,byte_1+byte_2会进S0,age=1
myGC();
Thread.sleep(1000);
System.out.println("111111=========================================");
//执行后,byte_1+byte_2会进S1,age=2
myGC();
Thread.sleep(1000);
System.out.println("222222=========================================");
// 执行后,byte_1+byte_2会进S0,age=3
myGC();
Thread.sleep(1000);
System.out.println("3333333=========================================");
// 执行后,byte_1+byte_2会进S1,age=4
myGC();
Thread.sleep(1000);
System.out.println("444444444=========================================");
//因为已经达到MaxTenuringThreshold=4阈值,因此之前age=4的对象会被晋升到老年代
//可以看到新生代垃圾回收后的空间有明显的下降
myGC();
Thread.sleep(1000);
System.out.println("555555555=========================================");
// byte_3+byte_4+byte_5为3M ,注意,byte_1和byte_2已经在老年代了
byte[] byte_3 = new byte[1024 * 1024];
byte[] byte_4 = new byte[1024 * 1024];
byte[] byte_5 = new byte[1024 * 1024];
//S区所有age的对象大小超过60%阈值,达到TargetSurvivorRatio=60, 重置new threshold=1
myGC();
Thread.sleep(1000);
System.out.println("66666666666=========================================");
byte[] byte_6 = new byte[1024 * 1024]; //这个对象在下次GC时会在S区,不会进入老年代
//虽然未达到MaxTenuringThreshold=4,但是已经满足TargetSurvivorRatio=60,S区之前的age1、age2、age3、age4的对象都进入老年代,重置new threshold=4; 这里区别byte_6的内存情况
myGC();
System.out.println("7777777777=========================================");
}
/**
* 产生40M大小,From会被占满,会触发垃圾回收
*/
private static void myGC() {
for (int i = 0; i < 40; i++) {
// 1M
byte[] myarr = new byte[1024 * 1024];
}
}
}
使用的VM参数如下:
-verbose:gc
-Xmx200m
-Xmn50m
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=4
-XX:+PrintGCDateStamps
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:TargetSurvivorRatio=60
-XX:+PrintTenuringDistribution
运行结果可通过程序直接得出,一些细节参考代码注释。
2022-02-21T01:08:02.388-0800: [GC (Allocation Failure) 2022-02-21T01:08:02.388-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 4 (max 4)
- age 1: 1471672 bytes, 1471672 total
: 40141K->1480K(46080K), 0.0009180 secs] 40141K->1480K(199680K), 0.0009636 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
111111=========================================
2022-02-21T01:08:03.392-0800: [GC (Allocation Failure) 2022-02-21T01:08:03.392-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 4 (max 4)
- age 1: 1744 bytes, 1744 total
- age 2: 1460000 bytes, 1461744 total
: 42006K->1571K(46080K), 0.0010912 secs] 42006K->1571K(199680K), 0.0011157 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
222222=========================================
2022-02-21T01:08:04.398-0800: [GC (Allocation Failure) 2022-02-21T01:08:04.398-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 4 (max 4)
- age 1: 345896 bytes, 345896 total
- age 2: 1744 bytes, 347640 total
- age 3: 1459864 bytes, 1807504 total
: 41692K->2018K(46080K), 0.0012447 secs] 41692K->2018K(199680K), 0.0012923 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
3333333=========================================
2022-02-21T01:08:05.409-0800: [GC (Allocation Failure) 2022-02-21T01:08:05.409-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 4 (max 4)
- age 1: 136 bytes, 136 total
- age 2: 345272 bytes, 345408 total
- age 3: 1744 bytes, 347152 total
- age 4: 1459560 bytes, 1806712 total
: 42730K->2094K(46080K), 0.0012483 secs] 42730K->2094K(199680K), 0.0012961 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
444444444=========================================
2022-02-21T01:08:06.418-0800: [GC (Allocation Failure) 2022-02-21T01:08:06.418-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 4 (max 4)
- age 1: 144 bytes, 144 total
- age 2: 136 bytes, 280 total
- age 3: 345216 bytes, 345496 total
- age 4: 1744 bytes, 347240 total
: 42815K->780K(46080K), 0.0042800 secs] 42815K->2248K(199680K), 0.0043233 secs] [Times: user=0.01 sys=0.01, real=0.01 secs]
555555555=========================================
2022-02-21T01:08:07.430-0800: [GC (Allocation Failure) 2022-02-21T01:08:07.430-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 1 (max 4)
- age 1: 3145920 bytes, 3145920 total
- age 2: 144 bytes, 3146064 total
- age 3: 136 bytes, 3146200 total
- age 4: 345416 bytes, 3491616 total
: 41508K->3491K(46080K), 0.0021719 secs] 42976K->4961K(199680K), 0.0022176 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
66666666666=========================================
2022-02-21T01:08:08.440-0800: [GC (Allocation Failure) 2022-02-21T01:08:08.440-0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 4 (max 4)
- age 1: 1048736 bytes, 1048736 total
: 44223K->1063K(46080K), 0.0044809 secs] 45693K->5949K(199680K), 0.0045236 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
7777777777=========================================
Heap
par new generation total 46080K, used 22137K [0x00000007b3800000, 0x00000007b6a00000, 0x00000007b6a00000)
eden space 40960K, 51% used [0x00000007b3800000, 0x00000007b4c94870, 0x00000007b6000000)
from space 5120K, 20% used [0x00000007b6500000, 0x00000007b6609ef0, 0x00000007b6a00000)
to space 5120K, 0% used [0x00000007b6000000, 0x00000007b6000000, 0x00000007b6500000)
concurrent mark-sweep generation total 153600K, used 4886K [0x00000007b6a00000, 0x00000007c0000000, 0x00000007c0000000)
Metaspace used 3704K, capacity 4536K, committed 4864K, reserved 1056768K
class space used 415K, capacity 428K, committed 512K, reserved 1048576K
Process finished with exit code 0