JVM垃圾回收之垃圾回收器,程序员必须掌握的知识

时间:2022-07-24
本文章向大家介绍JVM垃圾回收之垃圾回收器,程序员必须掌握的知识,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

垃圾回收器分为哪几种

如果说垃圾回收算法是内存回收的方法论,那么垃圾收集器就是具体实现。jvm会结合针对不同的场景及用户的配置使用不同的收集器。 新生代收集器 Serial、ParNew、Parallel Scavenge 老年代收集器 Serial Old、Parallel Old、CMS收集器 特殊收集器 G1收集器[新型,不在年轻、老年代范畴内

新生代收集器

Serial收集器

Serial是发展最久也是最基本的收集器,在jdk1.3的时候只能采用Serial垃圾回收器,他是单线程回收器,在收集的时候必须停掉其他线程,等待收集工作完成,其他线程才能工作,应用在新生代复制算法,且在桌面应用比较多(单线程服务器上,推内存比较小的应用使用效率比较高)

当用户线程在新生代要进行回收,这个时候就会进行STW(stop the world)操作,将其他线程全部暂停,由当前单线程进行回收垃圾,当回收完了之后,就会打开其他线程,然后继续执行用户线程

注意:这种回收器,在堆空间比较大的时候,回收的效率会非常低

ParNew收集器

ParNew收集器和Serial收集器区别不是很大,唯一的就是在Serial收集器上做了改进的,将串行回收改为并行回收(多线程回收),以此来减少SWT的时间。

Parallel Scavenge收集器(简称PS收集器)

采用的复制算法,和ParNew一样支持多线程 但是该收集器更注重吞吐量 对于用户客户端,适合使用GC暂停时间短,不然会因为卡顿而导致交互界面卡顿很影响用户体验 对于后台来说,高吞吐量可以高效的利用CPU快速完成程序计算任务

吞吐量:用户代码时间 / (用户代码执行时间 + gc暂停时间) 可以通过以下两个参数,来控制暂停时间,以及吞吐量大小。

-XX:MaxGCPauseMillis 垃圾回收器最大停顿时间
-XX:GCTimeRatio 吞吐量大小  (0,100) 默认最大99

如下图,我们可以看到JDK8,采用的就是PS收集器

老年代收集器

Serial Old收集器

和新生代的Serial一样为单线程,Serial的老年代版本,不过它采用"标记-整理算法"。

Parallel Old收集器

支持多线程,Parallel Scavenge的老年版本,jdk6开始出现, 采用"标记-整理算法"【老年代的收集器大都采用此算法】 在jdk6以前,新生代的Parallel Scavenge只能和Serial Old配合使用,而且Serial Old为单线程Server模式下会拖后腿【多核cpu下无法充分利用】,这种结合并不能让应用的吞吐量最大化。

Parallel Old的出现,结合Parallel Scavenge,真正的形成“吞吐量优先”的收集器组合。

CMS收集器

CMS收集器(Concurrent Mark Sweep)是以一种获取最短回收停顿时间为目标的收集器。【重视响应,可以带来好的用户体验,被sun称为并发低停顿收集器】,采用的标记/清除算法,并且支持并发

它的运作过程

1.初始标记:使用可达性分析法标记,标记老年代中直接与GC Roots关联的对象(会进行stw)
2.并发标记:会与用户线程同时运行,由前阶段标记过的对象出发,所有可到达的对象都在本阶段中标记。
3.并发预清理:并发预清理阶段仍然是并发的。在这个阶段,虚拟机查找在执行并发标记阶段新进入老年代的对象(可能会有一些对象从新生代晋升到老年代, 或者有一些对象被分配到老年代)。通过重新扫描,减少下一个阶段"重新标记"的工作,因为下一个阶段会Stop The World。
4.重新标记:标记那些因为用户程序继续运作产生的新生带跨带引用的垃圾对象
5.并发清除:清理所有的垃圾对象。
6.将原本的标记对象重置

总体上CMS是一款优秀收集器,但是也有它的缺点: 浮动垃圾:由于cms支持运行的时候用户线程也在运行,程序运行的时候会产生新的垃圾,这里产生的垃圾就是浮动垃圾,cms无法当次处理,得等下次才可以。

1.cms堆cpu特别敏感,cms运行线程和应用程序并发执行需要多核cpu,如果cpu核数多的话可以发挥它并发执行的优势,但是cms默认配置启动的时候垃圾线程数为 (cpu数量+3)/4,它的性能很容易受cpu核数影响,当cpu的数目少的时候比如说为为2核,如果这个时候cpu运算压力比较大,还要分一半给cms运作,这可能会很大程度的影响到计算机性能。 2.cms无法处理浮动垃圾,可能导致Concurrent Mode Failure(并发模式故障)而触发full GC 3.由于cms是采用"标记-清除“算法,因此就会存在垃圾碎片的问题,为了解决这个问题cms提供了 -XX:+UseCMSCompactAtFullCollection选项,这个选项相当于一个开关【默认开启】,用于CMS顶不住要进行full GC时开启内存碎片合并,内存整理的过程是无法并发的,且开启这个选项会影响性能(比如停顿时间变长)

G1收集器

G1垃圾回收器是在Java7 update 4之后引入的一个新的垃圾回收器。G1是一个分代的,增量的,并行与并发的标记-复制垃圾回收器。它的设计目标是为了适应现在不断扩大的内存和不断增加的处理器数量,进一步降低暂停时间(pause time),同时兼顾良好的吞吐量。G1回收器和CMS比起来,有以下不同: 1.G1垃圾回收器是compacting的,因此其回收得到的空间是连续的。这避免了CMS回收器因为不连续空间所造成的问题。如需要更大的堆空间,更多的floating garbage。连续空间意味着G1垃圾回收器可以不必采用空闲链表的内存分配方式,而可以直接采用bump-the-pointer的方式; 2.G1回收器的内存与CMS回收器要求的内存模型有极大的不同。G1将内存划分一个个固定大小的region,每个region可以是年轻代、老年代的一个。内存的回收是以region作为基本单位的; G1还有一个及其重要的特性:软实时(soft real-time)。所谓的实时垃圾回收,是指在要求的时间内完成垃圾回收。“软实时”则是指,用户可以指定垃圾回收时间的限时,G1会努力在这个时限内完成垃圾回收,但是G1并不担保每次都能在这个时限内完成垃圾回收。通过设定一个合理的目标,可以让达到90%以上的垃圾回收时间都在这个时限内。

G1的特点

1、并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。

2、分代收集:与其他收集器一样,分代概念在G1中依然得以保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。

3、空间整合:与CMS的“标记—清理”算法不同,G1从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。

4、可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。

G1执行原理

在G1之前的其他收集器进行收集的范围都是整个新生代或者老年代。而G1是面向整个堆。
它将整个Java堆划分为多个大小相等的独立区域(Region),但是G1有一种优先级的概念,就是可回收空间比较大的region会优先进行回收,这也是G1收集器能在有限的时间活得最高回收率的原因。
G1内部每一个region都有一个remember set来记录region内对象的指针,从而有计划地避免回收时对整个堆进行扫描。

运作过程

1.初始标记:标记能够于GC Roots对象的Region,需要stw,但耗时很短
2.并发标记:从GC Roots开始对堆中的可达性对象分析,找出存活对象,耗时长,但是是与用户线程并发执行
3.最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行
4.筛选回收::首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段可以做到与用户程序一起并发执行,但是因为只回收一部分Region,所以时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。

垃圾回收器与GC的关系与解释

Minor GC:新生代回收GC Major GC: 老年代回收GC Full GC: full gc是对新生代、老年代、永久代【jdk1.8后没有这个概念了】统一的回收。 Mixed GC:混合GC(收集整个young gen以及部分old gen的GC。只有G1有这个模式)

新生代GC回收原理,老年代同理

1.首先通过可达性分析,判断堆中的对象是否存活
2.新生代通过复制算法将Eden区存活的对象Copy到From区
3.通过Parallel Scavenge回收器来进行回收垃圾
4.Minor GC负责新生代的GC回收