一、什么是垃圾回收

垃圾回收(Garbage Collection,简称 GC),就是将存在于内存中的、不会再被使用的对象占有的空间进行清理。清理出来的空间可以供其他对象再利用。如果一直不进行垃圾回收,则有可能会导致内存溢出。

二、常用的垃圾回收算法

1、引用计数法

引用计数法是最经典也是最古老的垃圾回收算法。它的实现很简单,对于一个对象,只要有任何一个对象引用了它,那么它的计数器就加1;引用失效时,就减1。如果对象的引用计数器为0,则表示该对象可以被回收。

引用计数法有两个严重的问题:

  • 无法处理循环引用的问题。循环引用指的是两个对象互相引用,如对象 A 引用对象 B,同时对象 B 也引用了对象 A,但是 A 和 B 都没有被其他任何对象引用,这说明 A 和 B 其实是可以被回收的。由于 A 和 B 现在的引用计数都是1,所以它们不能被回收。

  • 引用计数会伴随一次加法或减法运算,会对系统性能造成一定影响。

ref.png

2、标记清除法

标记清除法把垃圾回收分为两个阶段:标记阶段清除阶段。在标记阶段,标记所有从根节点可达的对象;在清除阶段清除所有未被标记的对象。

标记清除法存在的问题是,垃圾回收之后的内存空间会产生很多碎片。

  • 回收前

mark1.png

(蓝色是可达对象,红色是不可达对象)

  • 回收后

mark2.png

可以看到,回收之后的空间是不连续的,这样对分配大对象非常不利。

3、复制算法

复制算法的核心是将内存分为两块,每次只使用其中一块。在垃圾回收时,将正在使用的内存中的存活对象复制到另一块对象中,然后清除其他对象。之后再次进行回收时则交换两个内存区域的角色。

复制算法可以保证回收之后的内存空间是连续的;如果在垃圾回收过程中存活对象较少,复制算法效率比较高。但是它的代价是将可用内存折半,这样也很难让人接受。

  • 回收前

copy1.png

(蓝色是可达对象,红色是不可达对象)

  • 回收后

copy2.png

4、标记压缩法

标记压缩法在标记清除法和复制算法的基础上做了一些改进。

首先,它也是从根节点开始标记所有可达对象,然后,它不是简单地清除不可达对象,而是将所有的存活对象压缩到内存的一端,然后开始清除垃圾。这样既避免了内存空间碎片,又不需要把内存空间折半。

  • 标记,压缩

compact1.png

(蓝色是可达对象,红色是不可达对象)

  • 清除

compact2.png