引用计数法:
原理:对于对象A,只要任意的对象引用了A,则A的引用计数器加一。当引用失效时,引用计数器减一。引用计数器的值为0时,对象A不可使用,回收。
缺点:1.无法处理循环问题。如果A引用了B,B同时引用了A。但A,B都不被其他任何对象引用。那么A,B都是不可达的。那么A,B不会被回收,从而引起内存泄漏。(java中未使用)
标记清除法:
原理:将垃圾回收分为两个阶段:标记阶段,清除阶段。
标记阶段:从根节点出发,标记所有可达的对象。
清除阶段:将所有未被标记的对象清除。
缺点:空间碎片问题。被清除的内存不是连续的。不连续的内存空间的效率低于连续的空间。
复制算法
原理:将原有的内存空间分为两块,一次只使用其中的一块。垃圾回收时,将正在使用的存活对象复制到未使用的内存块中,清除正在使用的内存块中的所有对象,交换两个内存的角色完成垃圾回收。
缺点:内存折半,单纯的复制算法难以接受。
适用于新生代。新生代垃圾对象多于存活对象。
标记压缩法
原理:在标记清除法的基础上进行改进。从根节点开始对所有可达对象进行标记,将所有存活对象压缩到内存的一端,清理边界外的所有空间。
优点:性价比高,无空间碎片,不需要两块相等的空间。
适用于:老年代
分代算法
原理:各种垃圾回收算法中没有一个可以完全替代其他算法,每一个都有其独特的优势和特点。因此,根据垃圾回收对象的特点对不同种类的对象使用不同的算法。
新生代对象:具有早生夕死的特点,大约90%的新建对象会很快被回收。适用复制算法
老年代对象:经过几次回收仍然存活,存活率较高。使用标记清除法或标记压缩法。
卡表:用于对应新生代和老年代的引用关系。新生代回收频率很高但耗时很短,老年代频率低,但耗时长。如果回收新生代时每次都要验证新生代对象是否被老年代对象引用会大大降低效率。卡表就是为了提高新生代的高频率回收的数据结构。卡表为一个比特位集合,每一个比特位表示老年代的某一个区域的所有对象是否持有新生代对象的引用。这样新生代GC时就不用花费大量时间扫描老年代对象。只有当卡表标记位为1时才需扫描。
分区算法
原理:将堆空间分为不同的小区间。每一个小区间都独立使用,独立回收。可以一次控制回收多个小区间。垃圾回收时会产生停顿现象,停顿时整个应用程序会被卡死,没有任何响应。每次回收若干个小区间,而不是整个堆空间,可以灵活的控制停顿时间减少一次GC产生的停顿。