目录
现在市面上充斥着许多对于JVM垃圾收集器教程,有零基础的,有专讲的 ... 这些教程或文章大都长篇大论的细扣字眼,内容繁多且没有重点,看过便会忘,本篇集结了9年老JAVA工作及面试经验,专讲面试和工作中使用到的,一站式讲解,帮助你疏通学习脉络,少走弯路。
学习本章节前,对于垃圾回收机制还不了解的话可以看看我的上篇文章进行回顾。传送门:Java高阶私房菜:JVM垃圾回收机制及算法原理探究-CSDN博客
什么是分代收集算法
针对不同生命周期的对象采用不同的垃圾回收策略,以达到更好的垃圾回收效果。年轻代空间多数对象存活时间短,可以高频地进行回收;而在老年代空间多数对象存活时间久,则需要低频回收。分代算法是根据回收对象的特点进行选择,根据上篇总结,年轻代适合标记-复制算法,老年代适合标记清除或标记压缩算法,通过将内存划分为不同的代,可以使得Minor GC的频率更高,更早地回收垃圾对象,减少Full GC的发生频率,提高整体性能。
JVM将内存分为年轻代和老年代,其中年轻代又分为Eden区和两个Survivor区。
年轻代:用于存放新生的对象,其中Eden区是新对象的分配区域,当Eden区满时,会触发Minor GC,将存活的对象移动到Survivor区,同时清空Eden区,Survivor区则用于存放经过一次Minor GC后存活的对象。
老年代:用于存放长时间存活的对象,当年轻代中的对象经过多次Minor GC后仍然存活,就会被移动到老年代,当老年代满时,会触发Full GC。
GC的分类和专业术语
Partical GC(部分收集)
新生代收集:对象从Young 区域消失(被回收)的过程称为“minor GC / Young GC”,Eden 的清理,S0\S1的清理都由于MinorGC,当YoungGen区内存不足时,就会触发minorGC。
老年代收集:对象从老年代中消失的过程,清理整合OldGen的内存空间,称为“Major GC/Old GC”,有些垃圾收集器 针对老年代单独回收,所以比较少用
Full GC(整堆收集)
清理整个堆空间,包括年轻代和老年代,可以理解为Major GC+Minor GC组合后进行的一整个过程,是清理JVM整个堆空间。
其实不用过多关心是叫Major GC还是Full GC,应该关注当前的 GC是否停止了所有应用程序的线程,许多Major GC 是由 Minor GC 触发的, 出现 Major GC通常出现至少一次的Minor GCMajorGC 的速度一般要比Minor GC慢 10倍不止。
其可手动调用System.gc( )触发, 但却不一定会立马执行Full GC,而只是提交了一个回收请求,由JVM的自动垃圾回收机制判断当前是否触发Full GC,即当老年代空间不足 , 通过Minor GC后进入老年代的平均大小大于老年代的可用内存。
需要注意的是,当执行Full GC时,它会暂停所有当前的应用线程,时间由回收效率而定,直至整个垃圾回收过程完成才恢复正常,它对系统的性能有较大影响,所以在生产环境中要尽量避免使用该方法,可以通过启动参数-XX:+ DisableExplicitGC来禁止调用System.gc()。内存的优化则尽量利用JVM垃圾回收策略来维护,包括日常的编码中不再使用的变量要置Null切断与堆空间的联系。
STW(Stop The World)
垃圾回收发生过程中,用户线程在运行至安全点(safe point)后,就自行挂起进入暂停状态,对外的表现就是卡顿,所以应尽量减少Full GC的次数,是Minor GC还是Major GC都会STW,区别只在于STW的时间长短。
JVM资料很多,有讲32位和64位的的虚拟机的参数,但是基本都不用32位操作系统(生产环境更是如此,如果仍使用32位操作系统就应该反省在这家公司的去留问题了),所以不用花时间去了解32位的。
什么是垃圾收集器
还是那句话,垃圾回收算法是内存回收的方法论,垃圾收集器则是内存回收的具体实现,目前Java规范中并没有对垃圾收集器的实现有任何规范,不同的厂商、不同的版本的虚拟机提供的垃圾收集器是不同的,主要讨论的是HotSpot虚拟机。
那么有没有最厉害的垃圾收集器呢?负责任的说其实不存在最厉害的垃圾收集器,只有在对应场景中最合适的垃圾收集器。
那为什么要有这么多的收集器呢?那是因为Java的使用场景很多,移动端,服务器等,然后内存里面对象存活时间不一样,需要针对不同的场景,提供不同的垃圾收集器,提高垃圾收集的性能。
垃圾收集器的分类及组合
新生代收集器
-
Serial 串行垃圾收集器
-
ParNew 年轻代的并行垃圾回收器
-
Parallel 并行垃圾收集器
老年代收集器
-
Serial Old 串行老年代垃圾器
-
Parallel Old 老年代的并行垃圾回收器
-
CMS (ConcMarkSweep)并发标记清除
整堆收集器:
G1:JDK9的默认垃圾收集器,以替代CMS。该收集器指出新生代和老年代不再是物理隔离的了(但还保留着新生代和老年代的概念),它们都是一部分Region (不需要连续)的集合,通过Region的动态分配方式实现逻辑上的连续。
ZGC:JDK11新引入的ZGC收集器,在该收集器中不管是物理上还是逻辑上,已经不存在新老年代的概念了,它们会被分为一个个page,当进行GC操作时会对page进行压缩,因此没有碎片问题。
那么那么多垃圾收集器,我们是否都要记住?作为新时代互联网人,还是那句话,我们只学有用的,淘汰的垃圾收集器我们不花太多时间。
垃圾收集器的组合
两个垃圾收集器之间如果存在连线,则说明它们可以搭配使用,图中:Serial old作为CMS出现"Concurrent Mode Failure"失败的后备预案
这里需要注意的是:
-
JDK8中默认使用: Parallel Scavenge GC + ParallelOld GC