0%

Java垃圾回收机制及其四大回收算法

什么是垃圾回收

垃圾回收(Garbage Collection)是JVM垃圾回收器提供的一种用于空闲时间不定时回收无任何应用的对象占据的内存空间的一种机制。

Java中的引用

强引用

软引用

弱引用

虚引用

四大GC算法

Tracing算法(标记-清除算法)

标记-清除算法是最基础的收集算法,为例解决引用计数法的问题而提出的。它使用了根集(Root Set)的概念,分为“标记”和“清除”两个阶段:首先标记出需要回收的对象,在标记完成后统一回收掉所有被标记的对象,它的标记过程就是前面的根搜索算法中判定垃圾对象的标记过程

优点:不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活对象比较多的情况下极为高效。

缺点:

  1. 标记和清除的过程效率不高。而且需要使用一个空闲列表来记录所有的空闲区域以及大小。
  2. 容易产生大量不连续的内存碎片。

Copying算法(复制算法)

复制算法是先将内存一分为二。一块是对象块,新进程都是装入对象块,当这一块用完后,就将还存活的对象都复制到另一块——空闲块上面。然后交换两个块的角色,清除垃圾。

优点:比标记-清除高效

缺点:不适合存活对象较多的场合,比如老年代

Compaction算法(标记-整理算法)

该算法标记的过程和标记-清除算法中的标记过程是一样的,但在标记后,不是直接将对象清理,而是让所有存活的对象都向一端移动,最后清理掉端边界以外的内存。

优点:

  1. 相比于复制算法,空间利用率高。
  2. 相比标记-清除算法,不会产生内存碎片。

缺点:GC暂停的时间更长,而且要更新引用地址

分代算法

分代算法是以上几种算法的综合引用。它先根据对象的存活周期将内存分为几块:新生代和老年代。在JDK8以前还有个永久代,不过JDK8以后永久代就被元空间取代了。
现在堆大小=新生代+老年代。比例新:老=1:2

新生代

几乎所有新生成的对象首先都是放在年轻代的,也有少部分大对象(如大数组)是直接分配老年代的。
新生代采用复制算法,但不再是将内存一分为二,而是划分为eden区、survivor 0区、survivor 1区,比例(8:1:1),这个也是可以调整的。
刚生成的对象一般是在eden区,当eden区满了后,就进行一次新生代GC。将存活的对象复制到survivor 0区,此时survivor 1区是空白的。接着将新生成的对象放到eden区,直到survivor 0区也满了,则将eden区和survivor 0区的存活对象复制到survivor 1区,清理eden和survivor 0,此时,survivor 0区变成空白的,survivor 0和survivor 1 区功能互换(即eden区满了则GC后放到survivor 1区)。
每当对象熬过一次新生代GC,则年龄+1,直到15(默认的,可修改)后,将其复制到老年代。

老年代

老年代中存放一些生命周期比较长的对象,或者是一些大对象。
老年代GC的频率比较低,标记存活率高。一般采用标记-整理算法

Minor GC、Major GC、Full GC

JVM在进行GC时,并非每次都针对上面三个内存区域(新生代、老年代;方法区)一起回收的,大部分时候回收的都是新生代。
针对HotSpot VM的实现,它里面的GC按照回收区域又分为两大种基本类型:一种是部分收集(Partial GC),另一种是整堆收集(Full GC)。
部分收集:不是完整收集整个Java堆的垃圾收集。其中又分为:
1、新生代收集(Minor GC / Young GC):只是新生代的垃圾收集
2、老年代收集(Major GC / Old GC):只是老年代的垃圾收集
注意:目前只有CMS GC会有单独收集老年代的行为,很多时候Major GC和Full GC混淆使用,需要具体分辨生部分收集还是整堆收集。
3、混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集。
注意: 目前只有G1 GC会有这种行为
整堆收集:收集整个Java堆和方法区的垃圾收集。

Minor GC触发机制

当Eden区空间不足时,就会触发Minor GC。因为Java对象大多都具备朝生夕死的特性,所以Minor GC频繁,一般回收速度也比较快。
Minor GC会引发STW,暂停其他用户线程,等垃圾回收结束,用户线程才恢复运行。

Major GC触发机制

当老年代空间不足时,会触发Major GC。如果出现了Major GC,经常会伴随至少一次的Minor GC(但并非绝对,Paralle Scavenge收集器的收集策略就有直接进行Major GC的策略选择过程)。
Major GC的速度一般会比Minor GC慢10倍以上,STW的时间更长。
如果Major GC后,内存还不足,就报OOM了。

Full GC触发机制

触发Full GC执行的情况有如下五种:
1、调用System.gc()时,系统建议执行Full GC,但不是必然执行的
2、老年代空间不足
3、方法区空间不足
4、通过Minor GC后进入老年代的平均大小大于老年代的可用内存
5、由Eden区、S0区向S1区复制时,对象大小大于S1区可用内存,则把该对象转存到老年代,切老年代可用内存小于该对象大小。
Full GC时开发或调优中尽量要避免的。这样STW时间会短一些

总结

流程图如下:

针对幸存者s0,s1区的总结:复制之后有交换,谁空谁是to。
关于垃圾回收:频繁在新生代收集,很少在老年代收集,几乎不在永久代/元空间收集。
⚠️注意以下几点:
1、每次YGC后,都是把Eden区和S0(或S1)区还存活的对象放到S1(或S0)区。也就是说,每次YGC后,Eden区都是空的
2、只有Eden区满了才会进行YGC,S0(或S1)区满了并不会触发YGC

垃圾回收器

垃圾回收器按执行机制划分主要有以下四种
四种垃圾回收器

串行垃圾回收器(Serial Garbage Collector)

通过持有应用程序的所有线程进行工作。它为单线程环境设置,只是用一个单独的线程进行垃圾回收,通过冻结所有应用程序线程进行工作。

并行垃圾回收器 (Parallel Garbage Collector)

是JVM默认的垃圾回收器。它使用多线程进行垃圾回收,在执行垃圾回收时也会冻结所有的程序线程。

##并发标记扫描垃圾回收器 (CMS Garbage Collector)
使用多线程扫描堆内存,标记需要清理的对象然后进行清理。

G1垃圾回收器 (G1 Garbage Collector)

G1收集器是最前沿的成果,是一款面向服务器端应用的收集器,支持并发和并行。
它将堆内存分割成不同的区域,并发的对其进行垃圾回收。

-------------------本文结束 感谢阅读-------------------
  • 本文作者: CeaserBorgia
  • 本文链接: https://timegoesby.top/Java-GC/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!