一、前言

​ 相对于c/c++,java、python等高级语言引进了Garbage Collector(GC)垃圾回收器,能实现内存垃圾的自动回收,虽然牺牲了一定的运行效率,但大大地提高了开发效率,那么问题来了,常用的GC都有哪些?常用的GC算法都有哪些?GC是如何定义和定位垃圾的呢?

二、What is Garbage

​ 在谈论垃圾回收算法和垃圾回收器之前,我们得先了解一下垃圾的基本概念。

(1)Garbage的定义

​ 在高级语言中通常将没有引用指向的内存定义为垃圾。

(2)Garbage的定位

​ 在python中,采用的是垃圾定位算法是reference count引用计数法,即记录每块内存被引用指向的数量,当指向某块内存的数量为0时,就把这块内存定义为垃圾,被GC自动释放(这让我想起了拓扑排序0.0),但这种算法有一个弊端,其无法解决“闭环”的情况,即多块内存相互引用形成闭环,与其他内存块无依赖。

​ 而在java中,则使用Root Searching根可达算法来定位垃圾,从程序的根(如main方法)开始,若无法抵达某块内存,就把该块内存判作垃圾,由GC进行释放,该算法很好的解决了”内存闭环“问题。

三、GC Algorithms

(1)Mark-Sweep

​ 标记清除法,将某块内存标记为垃圾,然后清除。算法的缺点,会产生碎片空间。

Mark-Sweep

(2)Copying

​ 拷贝法,将内存区分两半,每次运行时在一半中找出所有存活对象,然后整体性的复制到另外半边,同时排列好,然后把原来半边整体回收。算法的缺点是浪费内存。

Copying

(3)Mark-Compact

​ 标记压缩法,将标记为垃圾的内存回收,并且排列好。缺点是效率相对较低。

Mark-Compact

四、Garbage Collector

​ 三种GC算法都有自己的缺点和优点,三种的综合运用,诞生了各种各样的垃圾回收器。

Garbage-Collector

(1)Serial(单线程STW垃圾回收,处理<100MB)

​ New:A stop-the-world(STW),copying collector which uses a single GC thread.
​ Old:A stop-the-world(STW),mark-sweep-compact collector that uses a single GC thread.

​ 即当Serial工作时,内存中所有的业务线程都停止,等Serial清扫完后继续。

(2)Parallel(并行多线程PS+PO,处理<1G)

​ Parallel Scavenge:A stop-the-world(STW),copying collector which uses multiple GC threads.

​ Parallel Old:A stop-the-world(STW),mark-sweep-compact collector that uses multiple GC threads.

​ 与Serial的区别在于多个GC并行处理。

(3)Concurrent GC(处理几十G)

​ 从线程角度理解Concurrent GC,即GC和业务线程能同时运行。

​ ParNew:A stop-the-world(STW),copying collector which uses multiple GC threads.
​ It differs from “Parallel Scavenge” in that it has enhancements that make it useable with CMS

​ CMS:垃圾回收历史的重要节点!

五、java的垃圾回收机制

​ 如果要将一整块内存用统一的一种算法解决,其实是比较困难的,所以在jdk中,将内存划分为两个“年代”,new(新生代)和old(老年代),综合运用不同的垃圾回收器来管理内存空间。

​ 一个内存块在诞生时会被优先划分到新生代的eden区,在新生代区使用的GC算法是Copying算法,其中一次年轻代的清扫被称为YGC,其中90%的垃圾都会被回收,所以划分两个Copying区域没必要按照1:1的比例,其采用8:1:1的比例,清扫不掉的垃圾会被划分到survivor区。

​ 若某个垃圾很顽固,经历了多次清扫仍然存活,就会被划分到old老年区,因为老年区中的都是顽固垃圾,没必要再去一遍遍清扫,等到内存装不下了再用Mark Compact算法进行回收。

jdk-and-GC