说到GC垃圾回收,首先要知道什么是“垃圾”,垃圾就是没有再被使用的对象。怎样判定一个对象是不是垃圾(能不能被回收)?Java 虚拟机中使用一种叫作可达性分析的算法来决定对象是否可以被回收。
可达性分析就通过一组名为”GC Root"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,最后通过判断对象的引用链是否可达来决定对象是否可以被回收。
GC Root指的是:
- Java 虚拟机栈(局部变量表)中的引用的对象。也就是正在运行的方法中的局部变量所引用的对象
- 方法区中静态引用指向的对象。也就是类中的static修饰的变量所引用的对象
- 方法区中常量引用的对象。
- 仍处于存活状态中的线程对象。
- Native 方法中 JNI 引用的对象。
在标记出对象是否可被回收后,接下来就需要对可回收对象进行回收。基本的回收算法有:标记-清理、标记-整理与复制算法。
- 标记清除算法:从”GC Roots”集合开始,将内存整个遍历一次,保留所有可以被 GC Roots 直接或间接引用到的对象,而剩下的对象都当作垃圾对待并回收,过程分为标记和清除两个步骤
- 标记整理算法:与标记-清除不同的是它并不简单地清理未标记的对象,而是将所有的存活对象压缩到内存的一端。最后,清理边界外所有的空间
- 复制算法:将现有的内存空间分为两快,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中。之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收
现代虚拟机采用分代机制来进行垃圾回收,根据对象存活的周期不同,把堆内存划分为不同区域,不同区域采用不同算法进行垃圾回收。
分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。
总结在JVM中一般采用可达性分析法进行是否可回收的判定,确定对象需要被回收后,对象在哪个代际将会采用不同的垃圾回收算法进行回收,这些算法包括:标记-清除,标记-整理与复制算法。
而之所以采用分代策略的原因是:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。 如果每次垃圾回收都是对整个堆空间进行回收,花费时间相对会长,而对于生命周期长的对象而言,这种遍历是没有效果的,因为可能进行了很多次遍历,但是他们依旧存在。