一、什么是垃圾回收
垃圾回收
(Garbage Collection,简称 GC
),就是将存在于内存中的、不会再被使用的对象占有的空间进行清理。清理出来的空间可以供其他对象再利用。如果一直不进行垃圾回收,则有可能会导致内存溢出。
二、常用的垃圾回收算法
1、引用计数法
引用计数法
是最经典也是最古老的垃圾回收算法。它的实现很简单,对于一个对象,只要有任何一个对象引用了它,那么它的计数器就加1;引用失效时,就减1。如果对象的引用计数器为0,则表示该对象可以被回收。
引用计数法有两个严重的问题:
-
无法处理循环引用的问题。
循环引用
指的是两个对象互相引用,如对象 A 引用对象 B,同时对象 B 也引用了对象 A,但是 A 和 B 都没有被其他任何对象引用,这说明 A 和 B 其实是可以被回收的。由于 A 和 B 现在的引用计数都是1,所以它们不能被回收。 -
引用计数会伴随一次加法或减法运算,会对系统性能造成一定影响。
2、标记清除法
标记清除法
把垃圾回收分为两个阶段:标记阶段
和清除阶段
。在标记阶段,标记所有从根节点可达的对象;在清除阶段清除所有未被标记的对象。
标记清除法存在的问题是,垃圾回收之后的内存空间会产生很多碎片。
- 回收前
(蓝色是可达对象,红色是不可达对象)
- 回收后
可以看到,回收之后的空间是不连续的,这样对分配大对象非常不利。
3、复制算法
复制算法
的核心是将内存分为两块,每次只使用其中一块。在垃圾回收时,将正在使用的内存中的存活对象复制到另一块对象中,然后清除其他对象。之后再次进行回收时则交换两个内存区域的角色。
复制算法可以保证回收之后的内存空间是连续的;如果在垃圾回收过程中存活对象较少,复制算法效率比较高。但是它的代价是将可用内存折半,这样也很难让人接受。
- 回收前
(蓝色是可达对象,红色是不可达对象)
- 回收后
4、标记压缩法
标记压缩法
在标记清除法和复制算法的基础上做了一些改进。
首先,它也是从根节点开始标记所有可达对象,然后,它不是简单地清除不可达对象,而是将所有的存活对象压缩到内存的一端,然后开始清除垃圾。这样既避免了内存空间碎片,又不需要把内存空间折半。
- 标记,压缩
(蓝色是可达对象,红色是不可达对象)
- 清除