GC 内存回收的三种基本方式
类似c和c++的语言中,内存由程序员手动管理,需要时请求操作系统分配,不需要时返还系统,虽然效率高,但是容易出错。
-
标记清楚方式
从根开始将可能被引用的对象用递归的方式进行标记,类似树的结构,然后将没有标记到的对象作为垃圾进行回收。
分两个阶段,第一阶段从根部开始打标记,第二阶段将全部对象按顺序扫描一遍,将没有标记的对象进行回收。
缺点:在分配了大量对象,只有小部分存活的情况下,还要对大量死亡对象进行扫描,消耗时间。
-
复制收集方式
从根开始将被引用的对象复制到另外的空间中,然后将旧空间废弃。没必要再扫描一遍。
优点:复制后按照引用的顺序重新分配内存,关系较近的对象放在距离较近的内存空间的可能性更高,性能得到提高;
缺点:复制一份开销比较大,在“存活”对象比例较高的情况下,反而比较不利。
-
引用计数方式
每个对象中保存该对象引用计数,引用发生增减时对计数进行更新,引用计数为0时回收。
优点:实现容易,不再被引用的时可立刻释放。
缺点:a. 无法释放循环引用,b. 必须在引用发生增减时对引用计数做出正确的增减,如果漏掉引发难找的内存错误,c. 不适合并行处理,多线程导致计数不一致,加锁带来开销。
Objective-c 使用引用计数方式,Perl 和 Python 它们为了避免循环引 用的问题,都配合使用了其他的 GC 机制。
改良的应用方式
-
分代回收
利用了一般性程序所具备的性质,即大部分对象都会在短时间内 成为垃圾,而经过一定时间依然存活的对象往往拥有较长的寿命,对诞生时间较短的“年轻”对象进行重点扫描。对象按照生成时间进行分代。
-
增亮回收
在对实时性要求很高的程序中,比起缩短 GC 的平均中断时间,往往更重视缩短 GC 的最 大中断时间,增量回收的过程是分步渐进式的, 可以将中断时间控制在一定长度之内。
-
并行回收
原理是在原有的程序运行的同时进行 GC 操作,这一点和增量回收是 相似的。并行回收可以利 用多 CPU 的性能,尽可能让这些 GC 任务并行(同时)进行。
总结:
改良方式是通过三重基础方式的融合。