(1)为对象添加一个引用计数器
(2)每当对象在一个地方被引用,则该计数器加 1,每当对象引用失效时,计数器减 1。
(3)当计数器为 0 的时候,就表明该对象没有被引用。
无法处理循环引用的问题。
(1)通过 “GC Roots” 的根节点开始,沿着引用链进行搜索。
(2)绿色部分的对象都在 GC Roots 的引用链上,就不会被垃圾回收器回收,
(3)灰色部分的对象没有在引用链上,就被判定为可回收对象。
把Java 堆分成两块,每次垃圾回收时只使用其中一块,然后把存活的对象全部移动到另一块区域。
(1)结合前面两个算法特点
(2)标记的存活对象移动到堆的一端
(3)清理存活对象以外的区域
(1)优点:避免了内存碎片,也不存在堆空间浪费
(2) 缺点:
每次进行垃圾回收的时候,都要暂停所有的用户线程;特别是对老年代的对象回收,则需要更长的回收时间,用户体验差。
(1)单行程(单线程)的Siri(serial)老(serial old)了,收集信息速度太慢了,于是派来了新( ParNew)的多行程的语音助手来帮忙。
(2)可是收集量还是不够大,于是又派来了斯克文(Parallel Scavenge)提高收集量,而且和之前派来了老(parallel Old)的一起收集很合拍。
(3)收集量越来越多累得他们不得不停顿休息。还好西姆斯(CMS)也来帮忙收集了。
而且他不仅停顿休息少而且收集量也大,只是有一点,收集完比较多碎片化的东西。
不过他找到朋友G1来帮他解决了这个问题。
(1)最基础、最悠久的收集器,是一个单线程工作的收集器。
(2)清理堆空间时,进行 Minor gc 和Full GC,所有的应用线程都会被暂停。
(1)是 Serial 收集器的多线程并行版本,同时使用多条线程进行垃圾收集。
(2)其余包括 Serial 收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与 Serial 收集器完全一致。
(1)新生代收集器,基于标记——复制算法实现,
(2)能够并行收集的多线程收集器,和 ParNew 非常相似。
(3)目标则是达到一个可控制的吞吐量(Throughput)。
备注:吞吐量
a.处理器用于运行用户代码的时间与处理器总消耗时间的比值。
b.如:虚拟机完成某个任务,用户代码加上垃圾收集总共耗费了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是 99%。
Serial 收集器的老年代版本,单线程收集器,使用 “标记-整理算法”。
是 Parallel Scavenge 收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。
Concurrent Mark Sweep
(1)目标是为了消除 Parallel 收集器和 Serial 收集器 Full gc 周期中的长时间停顿。
(2)在 Minor gc 时会暂停所有的应用线程,并以多线程的方式进行垃圾回收。
仅仅标记一下GC Roots能直接关联到的对象,速度很快。
a.从GC Roots的直接关联对象,开始遍历整个对象图的过程。
b.这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行;
a.是为了修正并发标记期间,因用户程序继续运作,而导致标记产生变动那一部分对象的标记记录,
b.这个阶段的停顿时间通常会比初始标记阶段稍长一 些,但也远比并发标记阶段的时间短;
a.并发清除阶段,清理删除掉标记阶段判断的已经死亡的 对象,
b.由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
(1)Garbage-First,垃圾优先。
(2)服务类型收集器,针对配备多核处理器及大容量内存的机器。
(3)可设置垃圾收集暂停时间,高吞吐量,CPU利用率高。
(4)G1保留了年轻代和老年代的概念,但不再是物理隔阂了,它们都是(可以不连续)Region的集合,年轻代和老年代会动态变化甚至相互转换。
(5)重要参数
a.XX:MaxGCPauseTimeMillis :
设置GC可以暂停虚拟机的最大时间量。
默认:停顿时间200ms
b.-Xmx - 允许虚拟机的最大堆空间。
(1)并行与并发
(2)分代收集
(3)空间整合
整体:基于标记-整理算法实现
局部:基于标记-复制算法实现
(4)可预测的停顿
G1除了追求低停顿(CMS也是)外,还能建立可预测的停顿时间模型(后台维护的优先列表)
(1)初始值只占堆内存5%
(2)若Eden区回收时间远小于-XX:MaxGCPauseMills设定的值,则增加年轻代的region,继续给新对象存放,不会马上做Young GC。
(3)若回收时间接近参数 -XX:MaxGCPauseMills设定值,则触发Young GC
(1)老年代的堆占有率达到参数-XX:InitiatingHeapOccupancyPercent设定的值触发
(2)回收所有的年轻代和部分老年代(根据筛选回收阶段计算优先级后排序)以及大对象区。
(3)正常情况G1的垃圾收集是先做MixedGC,主要使用复制算法,
需要把各个region中存活的对象拷贝到别的region里去,
拷贝过程中如果发现没有足够的空region能够承载拷贝对象就会触发一次Full GC。
停止系统程序,然后采用单线程进行标记、清理、压缩整理,以空闲出来一批Region,来供下一次MixedGC使用,这个过程非常耗时。
(1)50%以上的堆被存活对象占用
(2)对象分配和晋升的速度变化非常大:前提是大内存的主机才有优势,否则还不如其他
(3)垃圾回收时间特别长,超过1秒
(4)8GB以上的堆内存(建议值)
共2048个Region,内存太小的话每个Region也很小,很容易就超过Region的一半被识别为超大对象,这样Humongous区东西会很多,反而不能很好的进行GC收集
(5)停顿时间是500ms以内
-XX:+PrintCommandLineFlags -version
# 必备
# 开启GC
-verbose:gc (或-XX:+PrintGC)
# 开启打印GC详情
-XX:+PrintGCDetails
# 打印GC时间
-XX:+PrintGCDateStamps
# 打印对象分布情况
-XX:+PrintTenuringDistribution
# GC后打印堆数据
-XX:+PrintHeapAtGC
# 打印Reference处理信息:强引用/弱引用/软引用/虚引用/finalize
-XX:+PrintReferenceGC
# 打印STW时间
-XX:+PrintGCApplicationStoppedTime
# 可选
# 打印safepoint信息
-XX:+PrintSafepointStatistics
-XX:PrintSafepointStatisticsCount=1
# GC日志输出的文件路径(-Xloggc:D:/log/gcc.log)
-Xloggc:/path/to/gc-%t.log
# 开启日志文件分割
-XX:+UseGCLogFileRotation
# 最多分割几个文件,超过之后从头文件开始写
-XX:NumberOfGCLogFiles=14
# 每个文件上限大小,超过就触发分割
-XX:GCLogFileSize=100M
其他参数详细如下:
JVM入门教程第14讲:JVM参数之GC日志配置
(1)并发
是指GC可以在应用程序运行时执行工作,但是G1不能在应用程序运行时执行所有的工作,而且仍然有停止世界的事件。
(2)并行
是指一个GC可以使用多个线程来执行其工作。
吞吐量=用户代码运行时间/(代码运行时间+垃圾收集时间)
(1)使用复制算法,目标是达到一个可控制的吞吐量
(2)重要参数:-XX:UserAdaptiveSizePolicy
a.该参数激活后,不需要人工的指定新生代大小(-Xmn)、Eden与Surivivor区的比例,晋升老年代对象大小等参数
b.虚拟机会根据当前系统运行情况,收集性能监控信息,动态调整这些参数,以提供最合适的停顿时间、最大的吞吐量。
(1)使用标记-整理算法,支持多线程并行收集。
(2)弥补了之前Parallel Scavenge收集器与别的优秀的老年代收集器不搭的情况。
(1)内存效率(时间复杂度):复制算法>标记清除算法>标记整理(压缩)算法
(2)内存整齐度:标记整理(压缩)算法=复制算法>标记清除算法
(3)内存利用率:标记整理(压缩)算法=标记清除算法>复制算法
(1)Minor GC/Young GC:针对新生代的垃圾收集;
(2)Major GC/Old GC:针对老年代的垃圾收集。
(3)Full GC:针对整个 Java 堆以及方法区的垃圾收集。
(1)复制算法,收集间隔较短,年轻代堆空间紧张时会触发。
(2)初次被创建的对象存放在新生代的 Eden 区,当第一次触发 Minor GC,Eden 区存活的对象被转移到 Survivor区 的某一块区域。
(3)再次触发 Minor GC 的时候,Eden区的对象连同一块 Survivor 区的对象一起,被转移到了另一块 Survivor 区。
(1)标记整理算法,非常耗时,老年代堆空间满了触发。
(2)期间会停止所有线程等待 GC 的完成。
上一篇跳转 ---- JVM(一)常见知识点及概述 下一篇跳转 ---- JVM(三)性能调优及实战
参考链接1
参考链接2
随心所往,看见未来。Follow your heart,see light!
欢迎点赞、关注、留言,收藏及转发,一起学习、交流!