Java虚拟机的三个垃圾收集算法
标记–清除、标记–复制、标记–整理
》GC Roots:它是可达性分析的起点,哪些可以作为GC Roots的节点?
1. 栈帧局部变量表的引用对象
2. 方法区中静态引用的对象(引用类型静态变量)
3. 方法区中常量引用的对象
4. 本地方法中引用的对象
5. Java虚拟机的内部引用,如基本数据类型的Class对象、异常对象、类加载器
6. 被同步锁(Synchronized)持有的对象
7. 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存
》如何判定对象存活还是死亡?
如果在进行可达性分析后没有与GC Roots相连,那么该对象会被第一次标记,随后会进行一次筛选,条件是:是否有必要执行finalize()方法,假如对象没有覆盖finalize()方法,活着finalize()方法已经被虚拟机调用过,那么虚拟机将这两种情况都视为没有必要执行。确认对象死亡后,该对象会被放到一个名为F-Queue的队列中,稍后由一条虚拟机创建的低调度优先级的Finalizer线程去执行它们的finalize()方法。
标记–清除:
它是最早出现也是最基础的垃圾收集算法。
首先标记出需要回收的对象,标记完成后,统一回收掉所有被标记的对象(也可以标记活着的对象)
两个主要缺点:
1. 执行效率不稳定,当堆中存在大量对象,而且大部分是需要回收的,这时需要大量的标记和清除动作
2. 空间碎片化
标记–复制(优先采用它回收新生代):
将堆内存划分为两块,每次使用其中一块。垃圾收集时,将活着的对象复制到另一块上面,然后将使用的这块全部回收,复制到另一块上面的对象是连续排列的,也就没有了空间碎片化问题,缺点很明显空间少了一半。对象存活率高,该算法效率也很低
但根据“新生代的对象有98%熬不过第一轮收集”,就有了“Appel式回收”,
即HotSpot默认的8:1:1(Eden:Survivor0:Survivor1),每次使用Eden加一个Survivor,也就只有10%的空间闲置
标记–整理(老年代):
标记完成后,将活着的对象往内存空间的一端移动,然后将另一端清理掉。移动对象需要修正引用而且要Stop The World