JVM03--JVM垃圾收集机制的一些基本概念

前言

今天来学习下与JVM垃圾收集机制相关的一些基本概念。

如何判断对象是否存活

垃圾收集器首要的任务的任务就是判断哪些对象是存活的,哪些对象已经死去了(这里死去的意思是对象不再被任何途径使用)。

引用计数算法

引用计数算法是在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可能被使用的对象。
引用计数算法的缺点就是很难解决对象之间相互循环引用的问题。

可达性分析算法

通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索的过程所走过的路径称为“引用链”,如果某个对象到GC Roots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象不可能再被使用的。例如:通过:Objcet 5,Object 6已经Object 7三个对象,虽然互有关联,但是他们到GC Roots是不可达的,因此可以判定为是可以回收的对象。
JVM03--JVM垃圾收集机制的一些基本概念

固定的可作为GC Roots对象包括如下几种:

  1. 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程调用的方法堆栈中使用到的参数,局部变量、临时变量等
  2. 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量
  3. 在方法区中常量引用的对象,譬如字符串常量池里的引用
    4.在本地方法栈中JNI(即通常所说的Native方法)引用的对象
  4. Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如 NullPointException、OutOfMemoryError)等,还有系统类加载器。
  5. 所有被同步锁(synchronized关键字)持有的对象
    7.反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等

引用的分类

引用分为如下四种:

  1. 强引用: 强引用是指在程序代码之中普遍存在的引用赋值,即类似“Object obj=new Object()”这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象
  2. 软引用: 软引用是用来描述一些还有用,但非必须的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常前,会被这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。
  3. 弱引用: 弱引用也是用来描述那些非必须对象,但是他的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
  4. 虚引用: 一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。

回收方法区

方法区的垃圾收集主要回收两部分内容:废弃的常量和不再使用的类型。回收废弃常量
与回收Java堆中的对象非常类似。同时判断一个常量是否废弃还是相对简单,而要判断一个类型是否属于“不再被使用的类”的条件就比较苛刻了。需要同时满足下面三个条件。

  1. 该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。
  2. 加载该类的类加载器已经被回收,这个通常很难达成
  3. 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。

分代收集理论

分代收集理论,实质是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上。

  1. 弱分代假说:绝大多数对象都是朝生夕灭的。
  2. 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡
    收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储。显而易见,如果一个区域中大多数对象都是朝生夕灭,难以熬过垃圾收集过程的话,那么把他们集中放在一起,每次回收时只关注如何保留少量存活而不是去标记那些大量将要被回收的对象。就能以较低代价回收到大量的空间;如果剩下的都是难以消亡的对象,那把它们集中放在一块,虚拟机便可以使用较低的频率来回收这个区域。
    新生代:每次垃圾收集时都发现有大批对象死去,而每次回收后存活的少量对象,
    将会逐步晋升到老年代中存放。
    老年代:老年代里面的对象几乎个个都是在 Survivor 区域中熬过来的,它们是不会那么容易就 “死掉” 了的。
  3. 跨代引用假说:跨代引用相对于同代引用来说仅占极少数
    只需要在新生代上建立一个全局的数据结构(该结构被称为“记忆集”)这个结构把老年代划分为若干小块,标识出老年代的哪一块内存会存在跨代引用。此后当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入到GC Roots 进行扫描。

收集说明

部分收集(Partial GC):

指目标不是完整收集整个Java堆的垃圾收集。其中又分为:

  1. 新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。
  2. 老年代收集(Major GC/Old GC): 指目标只是老年代的垃圾收集。目前只有CMS收集器会有单独收集老年代的行为。
  3. 混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。
  4. 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。

参考

《深入理解Java虚拟机_JVM高级特性与最佳实践》