1).对象回收机制
    堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断哪些对象已经死亡(即不能再被任何途径使用的对 象)。
    1.引用计数法
    给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0 的对象就是不可能再被使用的。 这个方法实现简单,效率高。
    但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。
    所谓对象之间的相互引用问题,如下面代码所示:除了对象objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为0,于是引用计数算 法无法通知 GC 回收器回收他们。如下面的代码:

    1. public class ReferenceCountingGc {
    2. Object instance = null;
    3. public static void main(String[] args) {
    4. ReferenceCountingGc objA = new ReferenceCountingGc();
    5. ReferenceCountingGc objB = new ReferenceCountingGc();
    6. objA.instance = objB;
    7. objB.instance = objA;
    8. objA = null;
    9. objB = null;
    10. }
    11. }

    2.可达性分析算法
    将“GC Roots” 对象作为起点,从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未标记的 对象都是垃圾对象 GC Roots根节点:线程栈的本地变量、静态变量、本地方法栈的变量等等
    image.png
    3. 常见引用类型
    java的引用类型一般分为四种:强引用、软引用、弱引用、虚引用
    强引用
    普通的变量引用 1 public static User user = new User();
    软引用
    将对象用SoftReference软引用类型的对象包裹,正常情况不会被回收,但是GC做完后发现释放不出空间存放 新的对象,则会把这些软引用的对象回收掉。软引用可用来实现内存敏感的高速缓存。 1 public static SoftReference user = new SoftReference(new User()); 软引用在实际中有重要的应用,例如浏览器的后退按钮。按后退时,这个后退时显示的网页内容是重新进行请求还是从 缓存中取出呢?这就要看具体的实现策略了。
    (1)如果一个网页在浏览结束时就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建
    (2)如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出
    弱引用
    将对象用WeakReference软引用类型的对象包裹,弱引用跟没引用差不多,GC会直接回收掉,很少用 1 public static WeakReference user = new WeakReference(new User());
    虚引用
    虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系,几乎不用

    4).finalize()方法最终判定对象是否存活
    即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一 个对象死亡,至少要经历再次标记过程。 标记的前提是对象在进行可达性分析后发现没有与GC Roots相连接的引用链。
    1. 第一次标记并进行一次筛选。 筛选的条件是此对象是否有必要执行finalize()方法。 当对象没有覆盖finalize方法,对象将直接被回收。
    2. 第二次标记 如果这个对象覆盖了finalize方法,finalize方法是对象脱逃死亡命运的最后一次机会,如果对象要在finalize()中成功拯救自己,只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己赋值给某个类变量或对象的成员变量,那在第 二次标记时它将移除出“即将回收”的集合。如果对象这时候还没逃脱,那基本上它就真的被回收了。 注意:一个对象的finalize()方法只会被执行一次,也就是说通过调用finalize方法自我救命的机会就一次。

    如何判断一个类是无用的类
    方法区主要回收的是无用的类,那么如何判断一个类是无用的类的呢? 类需要同时满足下面3个条件才能算是 “无用的类” :
    1.该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
    2.加载该类的 ClassLoader 已经被回收。
    3.该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。