JVM垃圾回收机制的学习与分析(一、引用判断算法与引用类型)

引用计数法 & 可达性分析算法

  • 众所周知,C/C++,无自动回收机制,对象不用时需要手动释放,否则积累导致内存泄漏

  • 而Java、C#、Python、Go等支持对不再使用的对象进行回收

  • Java引入GC机制,主要负责对堆上的内存进行回收,简化了对象的释放,但同时也丧失了回收的及时性,因为回收操作不再又开发者做了。

  • 线程不共享的部分,随着线程的创建而创建,随着线程的死亡而销毁,不会发生内存泄漏。且栈里的每个栈帧,在方法执行完后直接弹栈并释放内存,都不用等到线程死亡。

方法区的回收

回收不再使用的类,即类的卸载阶段,类的卸载条件比较困难,如下

  • 类的所有实例对象全被回收,堆中再无它的对象或子类的对象

  • 加载类A的类加载器被回收

  • 类A的java.lang.Class对象没有任何地方在引用

//运行过程中打印类的加载信息
-XX:+TraceClassLoading   
//类被卸载的时候打印一句日志
-XX:+TraceClassUnloading  
堆对象回收

对象的回收,看方法中还有无对对象的引用,有两种判断方式

  • 引用计数法:为每个对象维护一个计数器,对象被引用就+1,置为null了就-1,JVM扫描堆内存,发现数值为0则回收
  • 可达性分析算法:普通对象A,经一个引用链可以到达GC Root对象,则A不可被回收

GC Root对象即垃圾回收的根对象 GC Root对象一般不会被回收,且JVM持有GC Root对象的List列表 GC Root对象包括:

  • 线程对象Thread(引用线程栈帧中的方法参数、局部变量等)
  • 系统类加载器加载的java.lang.Class对象(引用类中的静态变量)
  • 监视器对象(引用synchronized锁的对象)
  • native本地方法调用时使用的全局对象native本地方法调用时使用的全局对象

强软弱虚引用、终结器引用

强引用
  • 默认强引用,即把一个对象赋值给一个变量(也叫引用)
  • GC时,有强引用的对象不会被回收,即使OOM了
软引用
  • 内存足够时,不会被GC回收
  • 内存不足时,才被GC回收
  • 包装为软引用:new SoftReference<对象类型>(对象)
  • 软引用中的对象如果在内存不足时回收,SoftReference对象本身也需要被回收:
弱引用
  • 不管JVM内存是否够用,GC运行,弱引用对象均被回收。
  • 和软引用一样,也可搭配一个引用队列
  • 用于ThreadLocal应对内存泄漏
虚引用
  • 幽灵引用/幻影引用
  • 虚,形同虚设的意思
  • 和其他几种引用不一样,它不影响对象的回收规则
  • 仅有虚引用指向的对象,随时可能会被回收
  • 唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知
  • 虚引用get方法返回结果总为null
终结引用
  • 对象需要被回收时,终结器引用会关联这个对象,并放入Finalizer类的引用队列(无需手动编码,其内部配合引用队列使用)
  • 稍后会由FinalizerThread线程从队列中获取这个对象,并执行它的finalize方法
  • 在这个对象该第二次被回收时,才真正干掉这个对象