1. GC概述
1.1. 关于GC
GC(Garbage Collection),垃圾收集,伴随着高级语言应运而生。第一个真正使用GC的语言是1960年诞生于MIT的Lisp语言,发展到目前,GC机制已经相当完善;
2. 垃圾回收算法
2.1. 引用计数(Reference Counting)
引用计数是最为经典的垃圾回收算法,通过对象的引用计数来进行垃圾回收;引用计数算法原理很简单,对于一个对象A,只要有任何一个对象引用它,A的引用计数器就+1,当引用失效,则引用计数器-1,只要对象A的引用计数器值为0,则表示A对象不能在被引用到,就可以被GC掉;
但引用计数算法存在以下问题:1.引用计数有性能问题;2.循环引用问题得不到很好的解决;
引用计数算法在Java中并未被采用;
2.2. 标记-清除算法(Mark-Sweep)
标记清除算法是现代垃圾回收算法的基础,通过对象可达性分析(Reachability Analysis)来判断对象是否存活,分为二阶段进行:标记阶段和清除阶段;
- 在标记阶段
通过一些称之为
GC Roots
的根对象作为起始点进行搜索,搜索所走过的路径称之为引用链(Reference Chain),但一个对象到根对象没有任何引用链时,该对象是不可用的; - 清除阶段 清除所有未被标记的对象;
标记-清除算法存在2个弊端:
- 标记、清除过程的效率g听不高;
- 清除对象之后空间上存在多个不连续的内存碎片,对之后的对象分配和寻址存在很大的效率问题;
2.3. 标记-压缩算法(Mark-Compact)
标记-压缩算法适用于存活对象较多的场合(老生代),该算法在标记-清除算法的基础上做了部分优化(在清理完未标记对象后,会将所有存活的对象压缩到内存的一端);
2.4. 复制算法(Coping)
复制算法是一种相对高效的回收算法,牺牲了部分空间来换取时间,但不适合存活对象较多的场合(如老年代);
复制算法将内存分为等价的二块,每次只使用其中一块,在GC时,将正在使用的一块中的存活对象复制到未使用的内存块中,清除正在使用的内存块中的所有对象,二个内存块互换角色
现在商业虚拟机大多采用复制算法回收新生代对象,新生代对象绝大部分都可以被回收,所以并不需要按照1:1的比例来划分内存空间,通常划分为一块较大Eden空间和二块较小的Survivor空间(每次使用Eden和其中一块Survivor);
2.5. 分代手机算法(Generational Collection)
分代收集算法是根据各个年代的特定采用不同的垃圾回收算法,通常新生代和老年代的垃圾收集算法是不一样的;