JAVA垃圾回收算法
常见的垃圾回收算法有:引用计数法、标记清除法、标记压缩法、复制算法、分代算法等。
1.引用计数法
引用计数是历史最悠久的一种算法,最早George E. Collins在1960的时候首次提出,50年后的今天,该算法依然被很多编程语言使用。
1.1原理
采用引用计数的方式,每有一个地方引用,记为引用加一。如果一个对象的引用计数为零,表明此对象可被回收。
1.2 优缺点
优点:
1.实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,就可以直接回收。
2.在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报outofmember 错误。
3.区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象。
缺点:
1.每次对象被引用时,都需要去更新计数器,有一点时间开销。
2.浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
3.无法解决循环引用问题。(最大的缺点,导致应用性较差)
2.标记清除法
2.1原理
标记清除算法,是将垃圾回收分为2个阶段,分别是标记和清除。
标记:从根节点开始标记引用的对象。
清除:未被标记引用的对象就是垃圾对象,可以被清理。
根节点对象包括那些:
1:虚拟机栈(栈帧中的本地变量表)中引用的对象。
2: 本地方法栈中JNI(即一般说的native方法)引用的对象。
3: 方法区中的静态变量和常量引用的对象。
Ps:每个线程都会创建一个虚拟机栈,每调用一个方法就会为每个方法生成一个栈帧,用来存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法被调用和完成的过程,都对应一个栈帧从虚拟机栈上入栈和出栈的过程。虚拟机栈的生命周期和线程是相同的。
2.2 优缺点
效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要停止应用程序,对于交互性要求 比较高的应用而言这个体验是非常差的。
通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收的对象可能存在于内存的各个角落,所以 清理出来的内存是不连贯的
改进:在清理阶段,并不是简单的清理未标记的对象,而是将存活的对象压缩到内存的一端,然后清理边界以外的垃圾,但是会有一定的时间消耗。
2.3 应用
老年代一般是由标记清除或者是标记清除与标记整理的混合实现效率比较低
3.复制算法
3.1原理
复制算法的核心就是,将原有的内存空间一分为二,每次只用其中的一块,在垃圾回收时,将正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收。
3.2 优缺点
如果内存中的垃圾对象较多,需要复制的对象就较少,这种情况下适合使用该方式并且效率比较高,反之,则不适合。
3.3应用
通常用在年轻代垃圾回收当中。
4.其他
可达性分析算法: 以根对象集合(GC Roots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。
标记-压缩算法 老年代一般是由标记清除或者是标记清除与标记整理的混合实现
效率低速度慢,需要移动对象,但不会产生碎片。
标记-清除-压缩算法 标记清除-标记压缩的集合,多次GC后才Compact
使用于占空间大刷新次数少的养老区
总结
一般来说垃圾回收都会采用多种算法,不同算法有不同的应用场景。根据回收对象的特点,合理运用算法才是明智的选择。