Full GC 就是收集整个堆,包括新生代,老年代,永久代(在JDK 1.8及之后,永久代会被移除,换为metaspace)等收集全部部分的模式html
RednaxelaFX大在Major GC和Full GC的区别是什么?触发条件呢?- 知乎这个问题有关于 GC分类的回答:算法
针对 HotSpot VM的实现,它里面的GC其实准确分类有两种:segmentfault
针对不一样的垃圾收集器,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)网络
若是有永久代(perm gen),要在永久代分配空间但已经没有足够空间时,也要触发一次 full GC并发
System.gc(),heap dump带GC,其默认都是触发 full GC.jvm
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作并发收集。spa
Minor GC 是俗称,新生代(新生代分为一个 Eden区和两个Survivor区)的垃圾收集叫作 Minor GC。在 Oracle 高级研究员郑雨迪的极客时间专栏 《深刻拆解Java虚拟机》中也谈到 Minor GC,内容以下:
当 Eden 区的空间耗尽了怎么办?这个时候 Java虚拟机便会触发一次 Minor GC来收集新生代的垃圾,存活下来的对象,则会被送到 Survivor区。
简单说就是当新生代的Eden区满的时候触发 Minor GC
前面提到,新生代共有 两个 Survivor区,咱们分别用 from 和 to来指代。其中 to 指向的Survivor区是空的。
当发生 Minor GC时,Eden 区和 from 指向的 Survivor 区中的存活对象会被复制(此处采用标记 - 复制算法)到 to 指向的 Survivor区中,而后交换 from 和 to指针,以保证下一次 Minor GC时,to 指向的 Survivor区仍是空的。
注意: from与to只是两个指针,它们变更的,to指针指向的Survivor区是空的
Java虚拟机会记录 Survivor区中的对象一共被来回复制了几回。若是一个对象被复制的次数为 15 (对应虚拟机参数 -XX:+MaxTenuringThreshold),那么该对象将被晋升为至老年代,(至于为何是 15次,缘由是 HotSpot会在对象头的中的标记字段里记录年龄,分配到的空间只有4位,因此最多只能记录到15)。另外,若是单个 Survivor 区已经被占用了 50% (对应虚拟机参数: -XX:TargetSurvivorRatio),那么较高复制次数的对象也会被晋升至老年代。
当Survivor区的部分对象晋升到老年代后,老年代的占用量一般会升高。
注意:
在Minor GC过程当中,Survivor 可能不足以容纳Eden和另外一个Survivor中的存活对象。若是Survivor中的存活对象溢出,多余的对象将被移到老年代,这称为过早提高(Premature Promotion),这会致使老年代中短时间存活对象的增加,可能会引起严重的性能问题。再进一步说,在Minor GC过程当中,若是老年代满了而没法容纳更多的对象,Minor GC 以后一般就会进行Full GC,这将致使遍历整个Java堆,这称为提高失败(Promotion Failure)。至于解决办法,这就涉及到对应用程序的调优问题了,这里就不叙述了,若有兴趣,请自行查阅相关资料
Minor GC存在一个问题就是,老年代的对象可能引用新生代的对象,在标记存活对象的时候,就须要扫描老年代的对象,若是该对象拥有对新生代对象的引用,那么这个引用也会被做为 GC Roots。这至关于就作了全堆扫描。
HotSpot 给出的解决方案是 一项叫作 卡表 的技术。以下图所示:
卡表的具体策略是将老年代的空间分红大小为 512B的若干张卡,而且维护一个卡表,卡表本省是字节数组,数组中的每一个元素对应着一张卡,其实就是一个标识位,这个标识位表明对应的卡是否可能存有指向新生代对象的引用,若是可能存在,那么咱们认为这张卡是脏的,即脏卡。如上图所示,卡表3被标记为脏。
在进行Minor GC的时候,咱们即可以不用扫描整个老年代,而是在卡表中寻找脏卡,并将脏卡中的老年代指向新生代的引用加入到 Minor GC的GC Roots里,当完成全部脏卡的扫描以后,Java 虚拟机便会将全部脏卡的标识位清零。这样虚拟机以空间换时间,避免了全表扫描
除了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是渣渣级选手,若有错误之处,欢迎指教