官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html#garbage_first_garbage_collection
使用G1收集器时,java堆的内存布局与其他收集器有很大区别,它将整个java堆划分分为多个大小相等的独立区域,虽然还能有新生和老年代的概念,但是新生代和老年代不再是物理隔离的了。他们都是一部分Region的集合
每个Region大小都是一样的,可以是1M到32M之间的数值,但是必须保证是2的N次幂如果对象太大,一个Region放不下【超出Region大小的50%】,那么就会直接放到H中设置Region大小:-XX:G1HeapRegionSize=M
所谓Garbage-Frist,其实就是优先回收垃圾最多的Region区域
(1)分代收集(仍然保留了分代的概念)
(2)空间集合(整体上属于”标记-整理“算法,不会导致空间碎片)
(3)可预测的停顿(比CMS更先进的地方在于能让使用者明确一个长度为M毫米的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒)
工作过程可以分为如下几步
初始标记 标记以下GC Roots能够关联的对象,并且修改TAMS的值,需要暂停用户线程
并发标记 从GC Roots进行可达性分析,找出存活的对象,与用户线程并发执行
最终标记 修改在并发阶段因为用户程序的并发导致变动的数据,需要暂停用户线程
筛选回收 对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划。
-XX:+UseG1GC开启G1垃圾收集器
-XX:G1HeapReginSize设置每个Region的大小,是2的幂次,1MB-32MB之间
-XX:MaxGCPauserMillis最大停顿时间
-XX:ParallelGCThread并发GC工作的线程数
-XX:ConcGCThreads并发标记的线程数
-XX:InitiatingHeapOcccupancyPercent
默认45%,代表GC堆占用达到多少的时候开始垃圾收集
官网:https://docs.oracle.com/en/java/javase/11/gctuning/z-garbage-collector1.html#GUI
D-A5A42691-095E-47BA-B6DC-FB4E5FAA43D0
JDK11新引入的ZGC收集器,不管是物理还是逻辑上,ZGC中已经不存在新生老年代的概念了,会分为一个个page,当进行GC操作时会对page进行压缩,因此没有碎片问题只能在64位linux上使用,目前用的还比较少
(1)可以达到10ms以内的停顿时间要求
(2)支持TB级别的内存
(3)堆内存变大后停顿时间还在10ms以内
垃圾收集器分类
》Serial和Serial Old
只能有一个垃圾回收线程执行,用户线程暂停。
适用于内存比较小的嵌入式设备
【吞吐量优先】->Parallel Scanvenge,Parallel old
多条垃圾收集线程并行工作,但是此时用户仍然处于等待状态
适用于科学计算,后台处理等交互场景
(停顿时间优先】-》CMS,G1
用户线程和垃圾收集线程同时执行(但并不一定是并行,可能是交替执行的),垃圾收集线程在执行的时候不会停顿用户线程的运行。
适用于相对时间有要求的场景,比如web
吞吐量和停顿时间
停顿时间-》垃圾收集器进行垃圾回收终端应用执行响应的时间。
吞吐量-》运行用户代码时间/(运行用户代码时间+垃圾收集时间)
停顿时间越短就越适合需要和用户交互的程序,良好的响应速度能提升用户体验;
高吞吐量则可以高效地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务
小结:这两个指标也是评价垃圾回收器好处的标准
如何选择合适的垃圾收集器
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#
sthref28
优先调整堆的大小让服务器自己来选择
如果内存小于100M,使用串行收集器
如果是单核,并且没有停顿时间要求,使用串行或jvm自己选
如果允许停顿时间超过一秒,选择并行或jvm自己选
如果响应时间最重要,并且不能超过1秒,使用并发收集器
对于G1收集
JDK7开始,JDK8非常成熟,JDK9默认的垃圾收集器,适用新老生代,
是否使用G1收集器?
(1)50%以上的堆被存活对象占用
(2)对象分配和晋升的速度变化非常大
(3)垃圾回收时间比较长
全称Remembered Set记录维护Region中对象的引用关系
试想,在G1垃圾收集器进行新生代,的垃圾收集时,也就是Minor GC,假如该对象被老年代Region中所引用,这时候新生代的该对象就不能被回收,怎么记录?
不妨这样,用一个类似hash的结构,key记录region的地址,value表示引用该对象的集合,这样就能知道该对象被哪些老年代所引用,从而不能回收。
如何开启需要的垃圾收集器
这里jvm参数信息的设置大家不用关心,后面会写到
(1)串行
-XX:+UseSerialGC
-XX:+UseSerialOldGC
(2)并行(吞吐量优先):
-XX:+UseParallelGC
-XX:+UseParallelOldGC
(3)并发收集器(响应时间优先)
-XX:+UseConcMarkSweepGC
-XX:+UseG1GC