RednaxelaFX大在 Major GC和Full GC的区别是什么?触发条件呢?- 知乎 这个问题有关于 GC分类的回答:
针对 HotSpot VM的实现,它里面的GC其实准确分类有两种:
针对不同的垃圾收集器,Full GC的触发条件可能不都一样。 按HotSpot VM的serial GC的实现来看 ,触发条件是:
当准备要触发一次 young GC时,如果发现统计数据说之前 young GC的平均晋升大小比目前的 old gen剩余的空间大,则不会触发young GC而是转为触发 full GC(因为HotSpot VM的GC里,除了垃圾回收器 CMS的concurrent collection 之外,其他能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以不需要事先准备一次单独的young GC)
HotSpot VM里其他非并发GC的触发条件复杂一些,不过大致原理与上面说的其实一样。
而 在 Parallel Scavenge 收集器下,默认是在要触发 full GC前先执行一次 young GC ,并且两次GC之间能让应用程序稍微运行一小下,以期降低 full GC的暂停时间 (因为 young GC 会尽量清理了young gen的死对象,减少了 full GC的工作量)。 控制这个行为的VM参数是: -XX:+ScavengeBeforeFullGC 。
并发GC的触发条件就不一样, 以 CMS GC为例,它主要是定时去检查old gen的使用量,但使用量超过了触发比例就会启动一次 CMS GC,对old gen做并发收集 。
Minor GC 是俗称, 新生代(新生代分为一个 Eden区和两个Survivor区)的垃圾收集叫做 Minor GC 。在 Oracle 高级研究员郑雨迪的 极客时间专栏 《深入拆解Java虚拟机》 中也谈到 Minor GC ,内容如下:
当 Eden 区的空间耗尽了怎么办?这个时候 Java虚拟机便会触发一次 Minor GC 来收集新生代的垃圾,存活下来的对象,则会被送到 Survivor区。
前面提到, 新生代共有 两个 Survivor区,我们分别用 from 和 to来指代 。其中 to 指向的Survivor区是空的。
当发生 Minor GC时,Eden 区和 from 指向的 Survivor 区中的存活对象会被复制(此处采用标记 - 复制算法)到 to 指向的 Survivor区中,然后 交换 from 和 to指针,以保证下一次 Minor GC时,to 指向的 Survivor区还是空的 。
Java虚拟机会记录 Survivor区中的对象一共被来回复制了几次。 如果一个对象被复制的次数为 15 (对应虚拟机参数 -XX:+MaxTenuringThreshold),那么该对象将被晋升为至老年代 ,(至于为什么是 15次,原因是 HotSpot会在对象头的中的标记字段里记录年龄,分配到的空间只有4位,所以最多只能记录到15)。另外, 如果单个 Survivor 区已经被占用了 50% (对应虚拟机参数: -XX:TargetSurvivorRatio),那么较高复制次数的对象也会被晋升至老年代。
Minor GC存在一个问题就是,老年代的对象可能引用新生代的对象,在标记存活对象的时候,就需要扫描老年代的对象,如果该对象拥有对新生代对象的引用,那么这个引用也会被作为 GC Roots。这相当于就做了 全堆扫描 。
HotSpot 给出的解决方案是 一项叫做 卡表 的技术。如下图所示:
卡表的具体策略是 将老年代的空间分成大小为 512B的若干张卡,并且维护一个卡表,卡表本省是字节数组,数组中的每个元素对应着一张卡,其实就是一个标识位,这个标识位代表对应的卡是否可能存有指向新生代对象的引用 ,如果可能存在,那么我们认为这张卡是脏的,即 脏卡 。如上图所示,卡表3被标记为脏。
除了Full GC和Minor GC外,还有一种说法叫做 "Major GC":
Major GC通常是跟full GC是等价的,收集整个GC堆,但因为 HotSpot VM发展这么多年,外界对各种名词的解读已经完全混乱了,当有人说"Major GC"的时候一定要问清楚他想要指的是上面的 full GC还是 old GC
以上是 R大关于 Major GC的说法,比较权威的。在网上还流行着 另外一种说法就是 Major GC是对老年代的垃圾回收 。
以上的内容基本上是从 R大的知乎回答与 极客时间专栏 《深入拆解Java虚拟机》 总结来的,在总结过程中,也算是对 Full GC 与 Minor GC 有了一个基本的认识。
取之网络,再回馈之网络,本人对于JVM是渣渣级选手,如有错误之处,欢迎指教