自动回收机制(卷四)

Java中的自动回收机制。

自动内存管理机制

GC一般使用两种1.引用计数2.可达性分析。

  1. 引用计数:简单高效,但是无法解决循环引用问题。
  2. 可达性分析:从各个GC Roots向下遍历,当任一引用链都不可达时,判断为可回收对象。(可作为GC Roots:虚拟机栈中引用的对象,本地方法栈中引用的对象,方法区中的常量引用的对象,方法区中类静态属性引用的对象)

四种引用。

  • 强引用Strong:类似new出的对象,只要该对象还有强引用,永远不会被回收。
  • 软引用Soft:当内存充足时,不会被回收;当内存不足时,GC会先回收被软引用的对象,如果还是不足,抛OOM。
  • 弱引用Weak:被弱引用的对象只能存活到下一次GC之前。
  • 虚引用Phantom:不对对象的生存周期造成影响,为一个对象设置虚引用,目的是在对象被回收前收到一个系统通知。

对象的自我救赎,在java中,判决一个对象死亡,要经历两次标记。1.引用链中无该对象,虚拟机进行第一次标记,并进行一次筛选,筛选的条件为是否要执行finalize方法。如果没重写该方法或者已经执行过该方法,则直接进入死亡。

  • 如果判定需要执行finalize方法,则将对象放入一个F-Queue队列中,并在一个虚拟机建立的、优先级低的线程中执行。该方方法是自救的唯一机会,在此期间,GC对F-Queue中进行二次标记,只要重新关联上引用链的任一对象,就会在二次标记中被移除,从而实现自救。
  • 该方法是java诞生初期为了妥协C/C++程序员而做的让步。
  • 建议忘记改方法。

方法区的GC

判定一个类是否可回收三部曲

  1. 类的所有实例已回收
  2. 加载该类的ClassLoader已被回收
  3. 类对应的java.iang.Class对象没有被任何地方引用,就是说不能再通过反射来范围该类的方法。

GC算法

常用的GC算法1.标记-清除(Mark-Sweep)、2.标记-整理(Mark-Compact)、3.复制(Coping)、4.分代收集(Generational Collection)

  1. 标记清除:最基础的算法。不足点A.标记和清除两个过程效率都不高。B.内存碎片。
  2. 标记整理:在标记清除基础上,让所有存活对象都移动到一端,直接清理端边界的内存。
  3. 复制:高效简单,内存只用了一半。(新生代中大部分对象都是‘朝生夕死’,使用8:1:1的Eden、from、to这样内存只浪费10%,当Survivor空间不足时,需要老年代进行分配担保),适合只有少部分对象存活情况。
  4. 分代收集:依据对象存活周期将内存划分为几块。

枚举根节点

在枚举根节点时,不允许出现分析过程中对象引用关系不断变化,要保证一致性,俗称stop the world。

  • OopMap的作用,把对象内上特点偏移量上对应存储的类型计算出来,保存OopMap中。以此来进行准确式的GC。
  • Safepoint:只有在特定位置记录了OopMap的信息,俗称安全点。程序只有到达安全点才能暂停。安全点选定原则:是否具有让程序长时间运行的特征;如循环,方法调用,异常跳转ETC。
  • 让程序跑到最近的安全点暂停,有两种方式A抢先式,即发生GC时,先中断全部线程,如发现线程未在安全点,就恢复线程,让其跑到安全点,然后暂停。B主动式,不直接对线程操作,只是设置一个标识,线程执行时主动去轮询该标识,遇到标识为真就中断自己并挂起,轮询标识和安全点事重合的,再加上创建对象需要分配内存的地方。当需要暂停线程时,线程执行到test指令时会产生一个自陷异常信号,在异常处理器中暂停线程。
  • Safe Region:由于安全点只能出来运行中的线程,当线程处于Sleep或者Blocked时,程序无法响应中断。安全区域指的是在一段代码片段中,对象的引用关系不会发生变化。
  • 在线程进入安全区域前,首先标识自己进入SafeRegion,在线程离开安全区域时,判断是否完成GC,如果未完成,需要等待GC完成再离开,否则可以直接离开。