垃圾回收第一部分——对象已死?
一锅炖不下

垃圾收集需要考虑三件事情:

  • 哪些内存需要回收?——从回收区域上来看,伴随线程而生灭的程序计数器、虚拟机栈、本地方法栈是不需要回收的,需要回收的是共享的堆内存,而其中对象的生命周期是不确定的,因此更近一步地需要确定哪些对象需要被回收,这也是垃圾回收的第一步,即标记垃圾。
  • 什么时候回收?
  • 如何回收?

对于如何确定哪些对象存活,哪些对象需要被回收这个问题,一共有以下两种解决方案。

一、引用计数算法

实现原理:

对象中添加一个计数器,如果有其他对象引用该对象,计数器加一;引用失效时,计数器减一,当计数器值为零时,则该对象可以被垃圾回收。

优点:

  • 原理简单,判定效率高

缺点:

  • 有许多例外情况需要考虑(如循环引用问题),需要大量额外处理来保证它正确工作

二、可达性分析算法

当前主流的内存管理子系统都是通过可达性分析算法来判断对象是否存活的。

实现原理:

GC Roots作为根节点,通过引用关系向下递归搜索,如果对象从任何一个GC Roots都不可达,则该对象就已经去世了。

GC Roots类型:

  • 虚拟机栈中引用的对象,这些都是当前线程直接使用到的对象,当然是不能让它去世的

  • 在方法区中类静态属性引用的对象,这部分对象是类的特征,而不是对象的的属性,具有全局性

  • 在方法去中常量引用的对象,比如字符串常量池中的引用

  • JNI引用的对象

  • JVM内部的引用,这部分对象属于JVM不可分割的一部分如:

    • 基本数据类型对应的class对象
    • 常驻的异常的对象
    • 系统类加载器
  • 所有被同步锁持有的对象,要通过这个对象的对象头中的mark word来找到当前持有锁的线程,如果把这种对象回收了,那么多线程同步就出大问题了

  • 反映JVM内部情况的JMXBeanJVMTI中注册的回调、本地代码缓存等,这个部分我了解的较少,后续还需要取查一下