目录标题
1. JVM GC的种类
GC为两大种类型:
部分收集(Partial GC)
整堆收集(Full GC)
1.1 部分收集(Partial GC)
部分收集(Partial GC):不是完整收集整个Java堆的垃圾收集,其中又分为:
新生代收集(Minor GC/Young GC):只是新生代的垃圾收集
老年代收集(Major GC/Old GC):只是老年代的垃圾收集(只有CMS的concurrent collection是这个模式)
混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集,目前,只有G1 GC会有这种行为
1.2 整堆收集(Full GC)
整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集
注意:JVM在进行GC时,并非每次都对所有区域(新生代,老年代,方法区)一起回收的,大部分时候回收的都是指新生代
2. GC的触发机制
2.1 年轻代GC(Minor GC)触发机制
Eden区空间不足,会触发Minor GC。
Survivor区满不会触发GC(每次Minor GC 会清理年轻代的内存)
因为Java对象大多具备朝生夕死的特新,所以Minor GC非常频繁,一般回收速度也比较快.
Minor GC会引发STW,暂停其他用户线程,等垃圾回收结束,用户线程才恢复运行
2.2 minorGC过程详解
- 在初始阶段,新创建的对象被分配到Eden区,survivor的两块空间都为空。
- 当Eden区满了的时候,minor GC被触发 。
- 经过扫描与标记,存活的对象被复制到S0,不存活的对象被回收, 并且存活的对象年龄都增大一岁。
- 当Eden 和 s0区空间满了,S0的所有的数据都被复制到S1,需要注意的是,在上次minor GC过程中移动到S0中的两个对象在复制到S1后其年龄要加1。此时Eden区S0区被清空,所有存活的数据都复制到了S1区,并且S1区存在着年龄不一样的对象。
- 再下一次MinorGC则重复这个过程,这一次survivor的两个区对换,存活的对象被复制到S0,存活的对象年龄加1,Eden区和另一个survivor区被清空。
- 再经过几次Minor GC之后,当存活对象的年龄达到一个阈值之后(-XX:MaxTenuringThreshold默认是15),就会被从年轻代Promotion到老年代。
- 随着MinorGC一次又一次的进行,不断会有新的对象被promote到老年代。
2.3 Full GC触发机制
- 调用System.gc(),系统建议执行Full GC,但是不必然执行
- 老年代空间不足【 如果创建一个大对象,Eden区域当中放不下这个大对象,会直接保存在老年代当中,如果老年代空间也不足,就会触发Full GC。】
- 方法区空间不足
- Minor GC后进入老年代的大小大于老年代的可用内存
- Minor GC时由Eden区,from区向to区复制时,对象大小大于to区可用内存,则把对象转存到老年代,并且老年代的可用内存小于该对象大小(那要是GC之后还不够呢?那还用说:OOM异常送上)
2.4 总结
当Eden区没有足够的空间进行分配时,虚拟机会执行一次Minor GC,Minor Gc通常发生在新生代的Eden区,在这个区的对象生存期短,往往发生Gc的频率较高,回收速度比较快;
Full Gc/Major GC 发生在老年代,一般情况下,触发老年代GC的时候不会触发Minor GC,但是通过配置,可以在Full GC之前进行一次Minor GC这样可以加快老年代的回收速度。
3. 新生代和老年代
3.1 新生代复制算法
新生代通常存活时间较短基于Copying算法进行回收,所谓Copying算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中,对应于新生代,就是在Eden和FromSpace或ToSpace之间copy。新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。
3.2 老年代标记整理算法
老年代与新生代不同,老年代对象存活的时间比较长、比较稳定,因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,回收后对用空出的空间要么进行合并、要么标记出来便于下次进行分配,总之目的就是要减少内存碎片带来的效率损耗。
4. 对象进入老年代的四种情况
- 假如进行Minor GC时发现,存活的对象在ToSpace区中存不下,那么把存活的对象存入老年代
- 大对象直接进入老年代
假设新创建的对象很大,比如为5M(这个值可以通过PretenureSizeThreshold这个参数进行设置,默认3M),那么即使Eden区有足够的空间来存放,也不会存放在Eden区,而是直接存入老年代 - 长期存活的对象将进入老年代
如果对象在Eden出生并且经过1次Minor GC后仍然存活,并且能被To区容纳,那么将被移动到To区,并且把对象的年龄设置为1,对象没"熬过"一次Minor GC(没有被回收,也没有因为To区没有空间而被移动到老年代中),年龄就增加一岁,当它的年龄增加到一定程度(默认15岁,配置参数-XX:MaxTenuringThreshold),就会被晋升到老年代中 - 动态对象年龄判定
如果在From空间中,相同年龄所有对象的大小总和大于Survivor空间的一半,那么年龄大于等于该年龄的对象就会被移动到老年代,而不用等到15岁(默认)
来源:https://blog.csdn.net/weixin_42615068/article/details/102813947
https://blog.csdn.net/weixin_45525272/article/details/126370223
Major GC和Full GC的区别是什么?触发条件呢? - RednaxelaFX的回答 - 知乎
https://www.zhihu.com/question/41922036/answer/93079526