深入理解JVM - 垃圾收集

1. 概述

垃圾收集器 Garbage Collection。
垃圾收集器需要完成的三件事

  • 哪些内存需要回收
  • 什么时候回收
  • 如何回收

只有Java堆和方法区需要考虑内存回收,程序计数器、虚拟机栈、本地方法栈的内存分配和回收都具有确定性。

2. 如何判断对象已死

1. 引用计数法 Reference Counting

在对象中添加一个引用计数器,每当被其他对象引用,计数器+1,引用失效则计数器-1,当计数器值为0时表名该对象不可能再被使用。
原理简单、判定效率高,难以解决循环引用问题。

2. 可达性分析算法 Reachability Analysis

通过一系列称之为 GC Roots 的根对象作为起始集,从这些根对象开始,根据引用链关系向下搜索,搜索过程走过的路径称之为引用链 Reference Chain,如果某个对象到GC Roots间没有引用链相连,也即从GC Roots到这个对象不可达,则证明该对象不可再被使用。

GC Roots

  1. 虚拟机栈(栈帧中的局部变量表)中引用的对象,如参数、局部变量、临时变量等。
  2. 本地方法栈中Native方法引用的对象
  3. 方法区中类静态属性引用的对象,如Java类的引用型静态字段
  4. 方法区中常量引用的对象,如字符串常量池中的引用
  5. VM内部引用,如基本数据类型对应的Class对象,常驻异常对象(NPE、OOM),系统类加载器等
  6. 同步锁/监视器锁 synchronized 所持有的对象
  7. 反应 JVM 内部情况 JMXBean、JVMTI 中注册的回调、本地代码缓存等。

以上是固定 GC Roots,根据用户选择的垃圾收集器及当前回收的内存区域不同,还可以有其他临时性对象加入。如分代收集和局部回收(Partial GC),针对局部剧区域的回收,还需要考虑该区域内对象被其他区域对象引用。当然为了避免 GC Roots 的膨胀,都进行了各种优化处理。

3. 各种引用

强软弱虚四种引用。
强引用 Stringly Reference:最传统的引用,只要还可达,就不会被回收。
软引用 Soft Reference:OOM前对这些引用进行回收,若内存还不足才会OOM。SoftReference 类
弱引用 Weak Reference:只能生存到下一次 GC。WeakReference 类。
虚引用 Phantom Reference:虚引用的存在不影响对象本身的生存时间,只是在对象被回收时得到通知。PhantomReference 类。

4. 标记过程

要宣告一个对象 不可达,至少需要经历两次标记。
第一次判断不可达,判断 finalize 方法是否已重写或是否已被 VM 调用过。若没有,则放入 F-Queue 队列,由 VM 自动建立的,低优先级的 Finalizer 线程执行 finalize 方法。
第二次对F-Queue对象判断是否可达,若不可达则此对象宣告死亡。

finalize 释放资源的问题:执行时间不确定,若某对象 fianlize 执行缓慢甚至死循环,可能导致内存回收子系统的崩溃。

当对象不可达时,可在 finalize 中拯救自己一次。

5. 方法区回收

主要两部分内容:废弃的常量和不再使用的内存。
类不再使用

  • 实例全部已被回收
  • 加载该类的类加载器已被回收
  • 该类的 Class 对象没有被引用
    -Xnoclassgc、-verbose:class、-XX:+TraceClassLoading、-XX:+TraceClassUnLoading
posted @ 2022-04-14 21:50  YangDanMua  阅读(32)  评论(0编辑  收藏  举报