GC中基本概念

对象/头/域

对象

在GC里,对象表示”通过应用程序利用的数据的集合”。对象配置在内存空间中,GC会根据情况将配置好的对象进行移动或销毁操作。因此,对象是GC的基本单位。

对象由“头(header)”与“域(field)”组成

将对象中保存对象本身信息的部分称为“头”,主要包括以下信息:

  • GC运行所需信息(预先存有)
  • 对象的大小
  • 对象的种类

把对象使用者在对象中可访问的部分称为“域”,域中的数据类型大致分为2种:

  • 指针: 指向内存空间中某块区域的值
  • 非指针: 编程中直接使用值本身

mutator

mutator有改变某物的意思,即改变GC对象间的引用关系。它的实体即为“应用程序”,它进行的实际操作分为2种:

  • 生成对象
  • 更新指针

mutator在进行这些操作是,会为应用程序的用户进行一些处理,随着这些处理的推进,对象间的引用关系随之也会发生”改变”,伴随着这些变化会产生垃圾,而负责会后这些就是GC

堆是用于存放对象的内存空间,在java堆的实现是一种特殊的树型数据结构

活动对象/非活动对象

在已分配到堆中的对象,那些能通过程序引用的对象称为”活动对象”,反之,不能通过引用的对象称为”非活动对象”,也就是GC需要回收掉的部分

分配

分配(allocation)指的是在内存空间分配对象。
当堆被活动对象占满,运行GC也无法配置可用空间时,有以下两种选择:

  • 销毁所有计算结果,输出错误信息
  • 扩大堆,分配可用空间

分块

分块(chunk)在GC世界里指的是为利用对象而事先准备出来的空间。
初始情况下,堆被一个大的分块占据,然后根据mutator的要求把这个分块分割成合适的大小,作为(活动)对象使用。活动对象不久会转化为垃圾回收,此时这部分被回收的内存空间再次分为分块,为下次被利用做准备。周而复始…

graph LR
A[分块] --> B(活动对象)
B --> C{非活动对象}
C -->A

根是指向对象的指针的“起点部分”。
在Java中,可作为根的主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如栈帧中的本地变量表)中。

评价标准

评价GC算法性能时,采用以下4个标准:

吞吐量

吞吐量指的是单位时间内的处理能力,大概为 \(HEAP_SIZE/(GC TIME) -最大暂停时间\)

因执行GC而暂停执行mutator的最长时间,如mutator执行过程中,共GC了3次,分别耗时1s,5s,3s那么最大暂停时间为5s

堆使用效率

访问的局限性

具有引用关系的对象之间通常很可能存在连续访问的情况称为“访问的局限性”。

一般会把数据存放到内存中,当cpu访问数据时,仅把要使用的数据从内存中读取到缓存。与此同时,我们还将它附件的所有数据都读取到缓存中,从而压缩读取数据所需要的时间。

考虑到访问的局限性,把具有引用关系的对象安排到堆中相近的位置,就能提高在缓存中读取到想利用数据的概率。