HotSpot中最简单的生成级垃圾收集器——并行收集器,它能适合多种负载。

6.1 标记和清除

标记和清除算法的这一介绍性形式使用了一个分配对象链表来保存指向每个已经分配但尚未回收的对象的指针。整个垃圾收集算法如下:

  1. 循环遍历以分配链表,清空标记位
  2. 从GC根开始,寻找活跃对象
  3. 在达到的每个对象上设置一个标记位
  4. 循环遍历已分配链表,对于每个标记尚未设置的对象。
    1. 回收堆中内存,将其放回空链表
    2. 从已分配链表中移除该对象。

活跃对象通常是通过深度优先搜索来定位的,生成的对象图叫做活跃对象图。有时也叫做可达对象的传递传递闭包。

垃圾收集术语

全部停顿(STW)

在垃圾收集时,垃圾收集周期要求所有的应用线程停顿。这可以避免在垃圾收集时,应用程序代码破坏垃圾收集线程锁掌握的堆状态信息。

并发(concurrent)

垃圾收集线程可以在应用线程运行的时候运行,实现并发十分困难,而且计算成本也非常高。几乎没有算法是真正并发的。

并行(parallel)

  1. 有多个线程用于执行垃圾收集

精准(exact)

对于堆的状态,精确垃圾收集模式有足够的类型信息,从而保证所有的垃圾都能在一个周期内完成回收。

保守(conservative)

移动(mving)

在移动垃圾收集器中,对象在内存中的位置有可能变化,因此它们的地址是不稳定的。支持原始指针的缓冲不是特别适合移动收集器

压缩(compacting)

在收集周期结束时,以分配的内存(即存活的对象)被组织为一个单一的连续区域,并有一个指针用来指示可供写入对象的空闲的起始位置,压缩收集器可用避免内存碎片。

疏散(evacuating)

在收集周期结束是,已收集区域完全为空,所有的活动都被移动(或疏散)到另一个区域。

6.2 HotSpot运行时

6.2.1 对象的运行时表示

HotSpot通过一个叫做oop的结构来表示运行时Java对象,这是普通对象指针的简称,是C语言意义上的真正指针。这些指针可以放置在引用类型的局部变量中,在该变量中他们从Java方法的栈帧指向包含Java堆的内存区域。
有几种不同的数据结构组成了oop家族,而用于表示Java类的实例类型叫做instanceOop。
instanceOop的内存布局是从每个对象上都有的两个机器字的头部开始的,其中第一个是mark work,它是一个指针,指向特定于该实例的元数据,下一个是klass word,它指向类级别的元数据。
在Java7和之前的版本中,instanceOop的klass word指向一个名为PermGen的内存区域,它是Java堆的一部分。一般的规则是,Java堆中的任何东西都必须有一个对象头。在这些就的Java版本中,我们把元数据称为klassOop。klassOop的内存布局很简单,就是对象头后面紧跟的klass元数据。
从Java8开始,klass被保存在Java堆的主要部分之外,在这些Java版本中,klass子不需要对象头,因为他们指向Java堆之外。