《深入理解java虚拟机-JVM高级特性与最佳实践》读书笔记 p69-100 垃圾收集器与内存分配策略

 

周志明《深入理解java虚拟机-JVM高级特性与最佳实践》读书笔记 p69-100 垃圾收集器与内存分配策略

1.垃圾收集算法:

1.1 标记-清除算法 Mark-Sweep

首先标记需要清除需要回收的对象,在标记完成后统一回收所有被标记的对象。

两个过程效率都不高。标记清除之后会产生大量不连续额内存碎片。

 

1.2 复制算法

将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。每次是对整个半区进行内存回收。内存分配时也不用考虑内存碎片等复杂情况。只要移动堆顶指针,按顺序分配即可,实现简单,运行高效。

只是这种算法的代价是将内存缩小为原来的一半。

新生代对象95%是朝生夕死Hotspot虚拟机默认Eden和Survivor的大小比例是8:1.

当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Hanle Promotion)。

 

1.3 标记-整理算法

复制算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。

老年代一般不使用这种算法。

后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

 

1.4 分代收集算法

当代商业虚拟机的垃圾收集算法 都采用“分代收集” 算法。根据对象存活周期的不同将内存划分为几块,一般是把java堆分为新生代和老年代。

新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法;

老年代中因为对象存活率高、没有额外空间对他进行分配担保,必须使用“标记-清理”或"标记-整理"算法进行回收。

 

 

2.HotSpot算法实现

2.1 枚举根节点

GC停顿 stop the world

oopMap

2.2 安全点 Safe Point

 

抢占式中断:不需要线程的代码主动去配合,在GC发生时,首先把所有线程全部中断,如果发现有线程中断的地方不在安全点上,就恢复线程,让她跑到安全点上 。现在几乎没有虚拟机实现采用抢先是中断来暂停线程从而响应GC事件。

主动式中断:当GC需要中断线程时,不直接ui线程操作,仅仅简单的设置一个标志。各个线程执行时主动去轮询这个标志,发现中断标志为真是就自己中断挂起。轮询标志的地方和安全点是重合的。

 

2.3 安全区域 safe Region

一段代码片段之中,引用关系不会发生变化。在这个区域中额任意地方开始GC都是安全的。

在线程执行到 Safe Region的代码时,首先标识自己已经进入Safe Region,那样当在这段时间里JVM要发起gc时,就不用管标识自己为Safe Region状态的线程了,在线程要离开Safe Region时,他要检查系统是否已经完成了根节点枚举,或者是整个GC过程,如果完成了,那线程就继续执行,否则他就必须等待直到收到可以安全离开Safe Region的信号为止。

 

3.垃圾收集器

3.1 Serial 收集器 单线程收集器

只会使用一个cpu或一条手机线程去完成垃圾收集工作;

在进行垃圾收集时,必须暂停其他所有额工作线程,直到他收集结束。这项工作实际上是由虚拟机在后台Z自动发起和自动完成的,在用户不可见额情况下吧用户正常工作的线程全部停掉。

虚拟机运行在client模式下额默认新生代收集器/

 

3.2 ParNew收集器

Serial收集器的多线程版本。

除了Serial外,只有ParNew能与CMS收集器配合使用

 

3.3 Parallel Scavenge 收集器

新生代收集器,算法:复制算法 并行的多线程收集器。

关注点不同:

CMS等收集器关注点:尽可能缩短垃圾收集时用户线程的停顿时间。

Parallel Scavenge收集器关注点:达到一个可控制的吞吐量。

吞吐量:CPU用于运行代码的时间与CPU总消耗时间的比值。

 

停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。

高吞吐量可以高效的利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

 

控制吞吐量的参数:

-XX:MaxGCPauseMills: 控制最大垃圾收集停顿时间。 GC停顿时间缩短是以牺牲吞吐量和新生代空间换取的。

-XX:GCTimeRatio:直接设置吞吐量大小。垃圾收集时间占总时间的比率,相当于吞吐量的倒数。

 

因此,Parallel Scavenge也经常被称为“吞吐量优先”的收集器。

GC自适应的调节策略:

Parallel Scavenge收集器有一个参数-XX:UseAdaptiveSivePolicy,是开关参数,打开之后,就不需要手工指定新生代的大小(-Xmn),Eden与Survivor的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。

《深入理解java虚拟机 JVM高级特性与最佳实践》 p80

 

3.4 Serial Old收集器

Serial Old是Serial收集器的老年代版本,是一个单线程收集器。使用“标记-整理”算法。

意义在于:给Client模式下的虚拟机使用。

在Server模式下的两大用途:1.在jdk1.5以及之前的版本中与Parallel Scavenge收集器搭配使用

2.作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。

 

3.4 Parallel Old收集器

Parallel Old是Parallel Scavenge收集器的老年代版本。使用多线程和“标记-整理”算法

jdk1.6以后才开始使用。

在此之前,新生代的Parallel Scavenge和老年代Serial Old配置使用外别无选择(因为Parallel Scavenge无法与CMS配合工作),由于老年代Serial Old在服务端性能上的拖累,单线程的老年代手机无法充分利用服务器多CPU的处理能力,吞吐量甚至不如ParNew + CMS组合“给力”。

 

Parallel Old收集器出现后,“吞吐量优先”收集器终于有了比较名副其实的应用组合,在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge + Parallel Old收集器。

 

3.4 CMS收集器

(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。

适合 重视服务的响应速度,希望停顿时间最短的互联网站或者B/S系统的服务端 的应用的需求。

 

步骤:

初始标记 - 标记一下GC Roots能直接关联到的对象,速度很快。

并发标记 - GC Roots Tracing,可与用户线程同时工作。

重新标记 - 修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。时间比初始标记长,但比并发标记短。

并发清除 - 可与用户线程同时工作。

 

整个过程耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以总体上说,CMS收集器的内存回收过程始于用户线程一起并发执行的。

 

主要有点已经在名字中体现出来了:并发收集、低停顿。,一些文档中也称之为并发低停顿收集器(Concurrent Low Pause Collector)。

有以下三个缺点:

1.CMS收集器对CPU资源非常敏感,因为占用了一部分线程。

2.CMS收集器无法处理浮动垃圾,肯恶搞出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。

3.CMS是一款基于“标记清除”算法实现的收集器,收集结束会有大量空间碎片产生。老年代空间剩余很大,但无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。

-XX:+UseCMSCompactAtFullCollection开关参数:默认开启。用于在CMS收集器顶不住要继续宁Full GC开启时内存碎片的合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间不得不变长。

-XX:CMSFullGCsBeforeCompaction,用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,表示每次进入Full GC时都进行碎片整理)

 

3.5 G1收集器

Garbage-First G1收集器,

特点:并行与并发、分代收集、空间整合(整体”标记-整理“,局部”复制“,可预测的停顿)

避免在整个java堆中继续宁全区域的垃圾收集,G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。 这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。

步骤:

初始标记- 标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程。但耗时很短。,

并发标记 - 从GC Roots开始对堆中对象进行可达性分析,找到存活的对象,耗时较长,但可与用户线程并发执行。

最终标记 - 为了修正在并发标记期间因用户程序继续运作二导致标记产生变动的那一部分标记记录-》Remeber Set Logs -》Rememberd Set。 需要停顿线程,但是可并行执行。

筛选回收 - 首先对各个Region的回收价值和成本继续宁排序,根据用户所期望的GC停顿时间来指定回收计划。

 

3.6 内存分配与回收策略

自动内存管理:给对象分配内存 、 回收分配给对象的内存。

对象的内存分配,即在堆上分配,对象主要分配在新生代的Eden区上,如果i启动了本地线程分配缓冲,将按线程优先在TLAB上分配。 少数情况也可能直接分配在老年代,分配的规则不是百分之百固定的。其细节取决于当前使用的是哪一种垃圾收集器组合,还有虚拟机中与内存相关的参数的设置。

3.6.1 对象优先在Eden分配。

package GCTest; /** * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 * @author lxp * @version 1.0 * @date 2020/1/30 12:44 */ public class GcTestOne { private static final int _1MB = 1024 * 1024; public static void main(String[] args) { testAllocation(); } public static void testAllocation() { byte[] allocation1, allocation2, allocation3, allocation4; allocation1 = new byte[2 * _1MB]; allocation2 = new byte[2 * _1MB]; allocation3 = new byte[2 * _1MB]; allocation4 = new byte[4 * _1MB]; } }

运行结果

"D:\Program Files\java\jdk1.8\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 "-javaagent:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=58567:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\java\jdk1.8\jre\lib\charsets.jar;D:\Program Files\java\jdk1.8\jre\lib\deploy.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\localedata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunec.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\Program Files\java\jdk1.8\jre\lib\javaws.jar;D:\Program Files\java\jdk1.8\jre\lib\jce.jar;D:\Program Files\java\jdk1.8\jre\lib\jfr.jar;D:\Program Files\java\jdk1.8\jre\lib\jfxswt.jar;D:\Program Files\java\jdk1.8\jre\lib\jsse.jar;D:\Program Files\java\jdk1.8\jre\lib\management-agent.jar;D:\Program Files\java\jdk1.8\jre\lib\plugin.jar;D:\Program Files\java\jdk1.8\jre\lib\resources.jar;D:\Program Files\java\jdk1.8\jre\lib\rt.jar;E:\coding\Practice\out\production\Practice;E:\coding\Practice\lib\asm-5.0.3.jar;E:\coding\Practice\lib\cglib-2.2.jar;E:\coding\Practice\lib\asm-all-7.0.1.jar;E:\coding\Practice\lib\asm-tree-5.0.3.jar;E:\coding\Practice\lib\cglib-nodep-3.2.4.jar;E:\coding\Practice\lib\asm-analysis-5.0.3.jar" GCTest.GcTestOne [GC (Allocation Failure) [PSYoungGen: 6248K->776K(9216K)] 6248K->4880K(19456K), 0.0030607 secs] [Times: user=0.02 sys=0.02, real=0.00 secs] Heap PSYoungGen total 9216K, used 7157K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 77% used [0x00000000ff600000,0x00000000ffc3b5f8,0x00000000ffe00000) from space 1024K, 75% used [0x00000000ffe00000,0x00000000ffec2020,0x00000000fff00000) to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) ParOldGen total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000) Metaspace used 3448K, capacity 4496K, committed 4864K, reserved 1056768K class space used 376K, capacity 388K, committed 512K, reserved 1048576K Process finished with exit code 0

新生代 6248 变为776kb。总内存没有变化9216kb,因为三个对象是存活的,虚拟机没有找到可回收的对象。

GC发生的原因是,给4分配内存的收,发现Eden已经被占用了6MB,剩余空间已经不足以分配4所需的4MB内存,因此发生MinorGC,GC期间虚拟机又发现已有的3个3MB的对象全部无法放入Survivor空间,(Survivor空间只有1MB左右),所以通过分配担保机制提前转移到老年代去。

(GC日志与原书中不一致,是由于JDK版本不一致,应该是这样的。嗯)

 

3.6.2 大对象直接进入老年代。(大对象:需要大量连续内存空间的java对象,最典型的大对象就是那种很长的字符串以及数组, 大对象对虚拟机的内存分配来说就是一个坏消息,,更坏的是遇到一群”朝生夕灭“的大对象,经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的空间来”安置“他们)。

虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内容复制。(新生代采用复制算法收集内存)

 

package GCTest; /** * * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728 * @author lxp * @version 1.0 * @date 2020/1/30 14:03 */ public class BigObject { private static final int _1MB = 1024 * 1024; public static void main(String[] args) { testPretenureSize(); } private static void testPretenureSize() { byte[] allocation; allocation = new byte[4 * _1MB]; } }

 

"D:\Program Files\java\jdk1.8\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728 "-javaagent:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=58221:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\java\jdk1.8\jre\lib\charsets.jar;D:\Program Files\java\jdk1.8\jre\lib\deploy.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\localedata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunec.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\Program Files\java\jdk1.8\jre\lib\javaws.jar;D:\Program Files\java\jdk1.8\jre\lib\jce.jar;D:\Program Files\java\jdk1.8\jre\lib\jfr.jar;D:\Program Files\java\jdk1.8\jre\lib\jfxswt.jar;D:\Program Files\java\jdk1.8\jre\lib\jsse.jar;D:\Program Files\java\jdk1.8\jre\lib\management-agent.jar;D:\Program Files\java\jdk1.8\jre\lib\plugin.jar;D:\Program Files\java\jdk1.8\jre\lib\resources.jar;D:\Program Files\java\jdk1.8\jre\lib\rt.jar;E:\coding\Practice\out\production\Practice;E:\coding\Practice\lib\asm-5.0.3.jar;E:\coding\Practice\lib\cglib-2.2.jar;E:\coding\Practice\lib\asm-all-7.0.1.jar;E:\coding\Practice\lib\asm-tree-5.0.3.jar;E:\coding\Practice\lib\cglib-nodep-3.2.4.jar;E:\coding\Practice\lib\asm-analysis-5.0.3.jar" GCTest.BigObject Heap PSYoungGen total 9216K, used 6412K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 78% used [0x00000000ff600000,0x00000000ffc43128,0x00000000ffe00000) from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000) ParOldGen total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000) Metaspace used 3448K, capacity 4496K, committed 4864K, reserved 1056768K class space used 376K, capacity 388K, committed 512K, reserved 1048576K Process finished with exit code 0

 

上述执行结果与《深入理解java虚拟机》原书不同,因为该参数只针对Serial和ParNew两款收集器。Parallel Scavenge不认识这个参数。

通过在cmd执行java -XX:+PrintCommandLineFlags -version,

《深入理解java虚拟机-JVM高级特性与最佳实践》读书笔记 p69-100 垃圾收集器与内存分配策略

《深入理解java虚拟机-JVM高级特性与最佳实践》读书笔记 p69-100 垃圾收集器与内存分配策略

 

 

 

3.6.3 长期存活的对象将进入老年代。

如果对象在Eden出生并经过一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1.。对象在Survivor区中每”熬过“一次Minor GC,年龄就增加1岁,当他的年龄增加到一定程度(默认15岁),将会被晋升到老年代。 阈值设置:-XX:MaxTenuringThreshold。

package GCTest; /** * * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution * @author lxp * @version 1.0 * @date 2020/1/30 14:22 */ public class TenuringThreshold { private static final int _1MB = 1024 * 1024; public static void main(String[] args) { testTenuringThreold(); } @SuppressWarnings("unused") private static void testTenuringThreold() { byte[] allocation1, allocation2, allocation3; allocation1 = new byte[_1MB / 4]; // 什么时候进入老年代取决于XX:MaxTenuringThreshold设置 allocation2 = new byte[4 * _1MB]; allocation3 = new byte[4 * _1MB]; allocation3 = null; allocation3 = new byte[4 * _1MB]; } }

 

"D:\Program Files\java\jdk1.8\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution "-javaagent:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=51973:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\java\jdk1.8\jre\lib\charsets.jar;D:\Program Files\java\jdk1.8\jre\lib\deploy.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\localedata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunec.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\Program Files\java\jdk1.8\jre\lib\javaws.jar;D:\Program Files\java\jdk1.8\jre\lib\jce.jar;D:\Program Files\java\jdk1.8\jre\lib\jfr.jar;D:\Program Files\java\jdk1.8\jre\lib\jfxswt.jar;D:\Program Files\java\jdk1.8\jre\lib\jsse.jar;D:\Program Files\java\jdk1.8\jre\lib\management-agent.jar;D:\Program Files\java\jdk1.8\jre\lib\plugin.jar;D:\Program Files\java\jdk1.8\jre\lib\resources.jar;D:\Program Files\java\jdk1.8\jre\lib\rt.jar;E:\coding\Practice\out\production\Practice;E:\coding\Practice\lib\asm-5.0.3.jar;E:\coding\Practice\lib\cglib-2.2.jar;E:\coding\Practice\lib\asm-all-7.0.1.jar;E:\coding\Practice\lib\asm-tree-5.0.3.jar;E:\coding\Practice\lib\cglib-nodep-3.2.4.jar;E:\coding\Practice\lib\asm-analysis-5.0.3.jar" GCTest.TenuringThreshold Heap PSYoungGen total 9216K, used 6668K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 81% used [0x00000000ff600000,0x00000000ffc83138,0x00000000ffe00000) from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000) ParOldGen total 10240K, used 8192K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 80% used [0x00000000fec00000,0x00000000ff400020,0x00000000ff600000) Metaspace used 3448K, capacity 4496K, committed 4864K, reserved 1056768K class space used 376K, capacity 388K, committed 512K, reserved 1048576K Process finished with exit code 0

由于jdk1.8 perm 与1.6不同,所以PrintTenuringDistribution参数未起效。

3.6.4 动态对象年龄判定。

不一定对象年龄必须达到阈值设定菜呢个晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。

3.6.4 空间分配担保

老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行F ull GC。