深入理解JVM(学习过程) (27)

image-20200218170631737

阈值和垃圾收集器类型对于对象分配的影响实践分析 VM options: -verbose:gc //会输出详细的垃圾回收的日志 -Xms20M //堆容量的初始大小 -Xmx20M //堆容量的最大大小 -- 两个值一般设置为一样的,这样不会出现抖动的现象。 -Xmn10M //新生代的大小是10M -XX:+PrintGCDetails //打印出垃圾回收详细的信息 -XX:SurvivorRatio=8 //eden和 survivor的比例为8:1的比例。 -XX:PretenureSizeThreshold=4194304 // 大小的阈值 4M的大小 新建的对象大小超过4M直接在老年代生成 -XX:+UseSerialGC //阈值的使用,需要搭配串行垃圾的收集器 -不添加此参数,上一个参数不起作用。 /** PretenureSizeThreshold: 设置对象超过多大时,直接在老年代进行分配空间 */ // 执行前添加上述参数 public class MyTest2 { public static void main(String[] args) { int size = 1024 * 1024; // 1M 的容量 byte[] myAlloc1 = new byte[5 * size]; // 创建之后每一个元素都是0 } } 数组的大小设置为5 和8 和10 的结果各不一样。 '使用之前介绍工具,可以查看当前执行的所有的内存分布情况及垃圾回收情况' System.gc(): 对JVM进行一次 Full GC 。 MaxtenuringThreshold与阈值的动态调整详解 -verbose:gc //会输出详细的垃圾回收的日志 -Xms20M //堆容量的初始大小 -Xmx20M //堆容量的最大大小 -- 两个值一般设置为一样的,这样不会出现抖动的现象。 -Xmn10M //新生代的大小是10M -XX:+PrintGCDetails //打印出垃圾回收详细的信息 -XX:+PrintCommandLineFlags // 打印命令行的标志,我们自己设置的启动参数 -XX:SurvivorRatio=8 //eden和 survivor的比例为8:1的比例。 -XX:MaxTenuringThreshold=5 //在可以自动调节对象晋升(Promote)到老年代阈值的GC中,设置该阈值的最大值。 -XX:+PrintTenuringDistribution // 打印出年龄为1的字节,年龄为2的字节,等等 /** MaxtenuringThreshold作用:在可以自动调节对象晋升(Promote)到老年代阈值的GC中,设置该阈值的最大值。该参数的默认值为15,CMS中默认值为6,G1中默认为15(在JVM中,该数值是由4个bit来表示的,1111,即15) 经历了多次GC后,新生代存货的对象会在From Survivor与To Survivor之间来回存放,而这里面的一个前提则是这两个空间有足够的大小来存放这些数据。在GC算法中,会计算每一个对象年龄的大小,如果达到某个年龄后发现总大小已经大于Survivor空间的50%,那么这时候就需要调整阈值,不能再继续等到默认的15次GC后才完成晋升,因为这样会导致Survivor空间不足,所以需要调整阈值,让这些存活对象尽快完成晋升。 */ // 执行前添加上述参数 public class MyTest3 { public static void main(String[] args) { int size = 1024 * 1024; // 1M 的容量 byte[] myAlloc1 = new byte[2 * size]; byte[] myAlloc2 = new byte[2 * size]; byte[] myAlloc3 = new byte[2 * size]; byte[] myAlloc4 = new byte[2 * size]; sout("hello world"); } } > 输出结果: > Task :MyTest3.main() // PrintCommandLineFlags 打印命令行的标志,我们自己设置的启动参数 -XX:InitialHeapSize=20971520 -XX:InitialTenuringThreshold=5 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=5 -XX:NewSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintTenuringDistribution -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC [GC (Allocation Failure) Desired survivor size 1048576 bytes, new threshold 5 (max 5) [PSYoungGen: 6815K->560K(9216K)] 6815K->6712K(19456K), 0.0036073 secs] [Times: user=0.04 sys=0.00, real=0.01 secs] [Full GC (Ergonomics) [PSYoungGen: 560K->0K(9216K)] [ParOldGen: 6152K->6426K(10240K)] 6712K->6426K(19456K), [Metaspace: 2798K->2798K(1056768K)], 0.0032972 secs] [Times: user=0.03 sys=0.00, real=0.00 secs] hello world Heap PSYoungGen total 9216K, used 2290K [ 0x00000007c0000000, 0x00000007c0000000) eden space 8192K, 27% used [0x00000007bf600000,0x00000007bf83c8d8,0x00000007bfe00000) from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000) to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000) ParOldGen total 10240K, used 6426K [ 0x00000007bf600000, 0x00000007bf600000) object space 10240K, 62% used [0x00000007bec00000,0x00000007bf246998,0x00000007bf600000) Metaspace used 2805K, capacity 4486K, committed 4864K, reserved 1056768K class space used 291K, capacity 386K, committed 512K, reserved 1048576K VM options: -verbose:gc //会输出详细的垃圾回收的日志 -Xms200M //堆容量的初始大小 -Xmn50M //新生代的大小是50M -XX:TargetSurvivorRatio=60 // 当Survivor空间占据了百分之60,将从新计算阈值。 -XX:+PrintTenuringDistribution // 打印出年龄为1的字节,年龄为2的字节,等等 -XX:+PrintGCDetails //打印出垃圾回收详细的信息 -XX:+PrintGCDateStamps //打印垃圾回收的时间戳 -XX:+UseConcMarkSweepGC //设置老年代的垃圾回收器 -XX:+UseParNewGC //设置新生代的垃圾回收器 -XX:MaxTenuringThreshold=3 //在可以自动调节对象晋升(Promote)到老年代阈值的GC中,设置该阈值的最大值。 // 综合的例子 public class MyTest4 { public static void main(String[] args) throws InterruptedException { byte[] byte_1 = new byte[512 * 1024]; byte[] byte_2 = new byte[512 * 1024]; myGc(); Thread.sleep(1000); System.out.println("1111111这里进行了垃圾回收"); myGc(); Thread.sleep(1000); System.out.println("2222222这里进行了垃圾回收"); myGc(); Thread.sleep(1000); System.out.println("3333333这里进行了垃圾回收"); myGc(); Thread.sleep(1000); System.out.println("4444444这里进行了垃圾回收"); byte[] byte_3 = new byte[1024 * 1024]; byte[] byte_4 = new byte[1024 * 1024]; byte[] byte_5 = new byte[1024 * 1024]; myGc(); Thread.sleep(1000); System.out.println("55555555这里进行了垃圾回收"); myGc(); Thread.sleep(1000); System.out.println("66666666这里进行了垃圾回收"); System.out.println("hello world"); } private static void myGc(){ // 真正会被收集的数组。方法调用介绍之后就会被垃圾回收。 for(int i = 0 ;i<40;i++){ byte[] byteArray = new byte[1024*1024]; } } } 》输出结果: > Task :MyTest4.main() 2020-02-18T19:44:39.419-0800: [GC (Allocation Failure) 2020-02-18T19:44:39.419-0800: [ParNew Desired survivor size 3145728 bytes,' new threshold 3 (max 3) - age 1: 1339912 bytes, 1339912 total : 40551K使用空间->1361K垃圾回收后大小(46080K总大小), 0.0014325 secs] 40551K->1361K(199680K), 0.0014891 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] //3145728 bytes = 3M 50*0.1*0.6 = 3M 1111111这里进行了垃圾回收 2020-02-18T19:44:40.430-0800: [GC (Allocation Failure) 2020-02-18T19:44:40.430-0800: [ParNew Desired survivor size 3145728 bytes,' new threshold 3 (max 3) - age 1: 584 bytes, 584 total - age 2: 1338144 bytes, 1338728 total : 42100K->1409K(46080K), 0.0012810 secs] 42100K->1409K(199680K), 0.0013128 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 2222222这里进行了垃圾回收 2020-02-18T19:44:41.435-0800: [GC (Allocation Failure) 2020-02-18T19:44:41.435-0800: [ParNew Desired survivor size 3145728 bytes,' new threshold 3 (max 3) - age 1: 72 bytes, 72 total - age 2: 584 bytes, 656 total - age 3: 1337920 bytes, 1338576 total : 41940K->1439K(46080K), 0.0005344 secs] 41940K->1439K(199680K), 0.0005592 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 3333333这里进行了垃圾回收 2020-02-18T19:44:42.441-0800: [GC (Allocation Failure) 2020-02-18T19:44:42.441-0800: [ParNew Desired survivor size 3145728 bytes, 'new threshold 3 (max 3) - age 1: 72 bytes, 72 total - age 2: 72 bytes, 144 total - age 3: 584 bytes, 728 total : 42170K->60K(46080K), 0.0027252 secs] 42170K->1397K(199680K), 0.0027533 secs] [Times: user=0.01 sys=0.01, real=0.00 secs] 4444444这里进行了垃圾回收 2020-02-18T19:44:43.454-0800: [GC (Allocation Failure) 2020-02-18T19:44:43.454-0800: [ParNew Desired survivor size 3145728 bytes, 'new threshold 1 (max 3) // 当前的年龄为1 重新设置了阈值 - age 1: 3145848 bytes, 3145848 total - age 2: 72 bytes, 3145920 total - age 3: 72 bytes, 3145992 total : 40794K->3087K(46080K), 0.0019052 secs] 42131K->4424K(199680K), 0.0019409 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 55555555这里进行了垃圾回收 2020-02-18T19:44:44.465-0800: [GC (Allocation Failure) 2020-02-18T19:44:44.465-0800: [ParNew Desired survivor size 3145728 bytes,' new threshold 3 (max 3) - age 1: 80 bytes, 80 total : 43823K->4K(46080K), 0.0026372 secs] 45160K->4413K(199680K), 0.0026724 secs] [Times: user=0.03 sys=0.00, real=0.00 secs] 66666666这里进行了垃圾回收 hello world Heap par new generation total 46080K, used 13912K [0x00000006c3200000, 0x00000006c3200000) eden space 40960K, 33% used [0x00000006c0000000, 0x00000006c0d95228, 0x00000006c2800000) from space 5120K, 0% used [0x00000006c2800000, 0x00000006c2801020, 0x00000006c2d00000) to space 5120K, 0% used [0x00000006c2d00000, 0x00000006c2d00000, 0x00000006c3200000) concurrent mark-sweep generation total 153600K, used 4409K [0x00000006c3200000, 0x00000006cc800000, 0x00000007c0000000) Metaspace used 2806K, capacity 4486K, committed 4864K, reserved 1056768K class space used 291K, capacity 386K, committed 512K, reserved 1048576K CMS垃圾回收器(新版本不建议使用)

CMS 垃圾回收器,复杂性比较高。在jdk新版本中不建议被使用。

CMS(Concurrent Mark Sweep):并发标记清除

枚举根节点概念

image-20200218195923581

安全点(Safepoint)概念

image-20200218200138311

程序执行时,并非在所有地方都能停顿下来开始GC,只有在达到安全点时才能暂停。

image-20200218200336027

安全点的选定基本上是以“是否具有让程序长时间执行的特征”为标准来进行选定的。

image-20200218200622418

主动式中断:轮询标志的地方和安全点是重合的。

安全区域(Safe Region)概念

image-20200218201116346

image-20200218201032392

CMS垃圾收集器深入详解

CMS收集器,以获取最短回收停顿时间为目标,多数应用于互联网站或者BS系统的服务器端上。

image-20200218201457879

image-20200218201733833

image-20200218202018765

初始标记的时候,会Stop the world , 此时没有用户线程执行。

并发标记的时候,可以与用户线程同时执行。

重新标记的时候,会Stop the world , 此时也没有用户线程执行。

并发清除的时候,可以与用户线程同时执行。

image-20200218202408587

停顿,停顿的是用户线程停顿的少。

image-20200218202435285

image-20200218202845482

CMS收集器收集步骤

初始标记

并发标记

并发预先清理阶段

并发可丢弃的阶段

最终的重新标记

并发清除

并发重置

出现Concurrent即代表GC线程可以和用户线程同步执行的阶段。

image-20200218203341656

image-20200218203454390

image-20200218203950009

image-20200218204548449

image-20200218204650881

image-20200218204749664

将标记拆分成了前5个阶段。

image-20200218204826808

image-20200218204843337

image-20200218204929489

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfdfy.html