GC算法基础相关概念

以下为《垃圾回收的算法与实现》中序章及相关概念读书笔记

1.GC 定义

GC: Garbage Collection, “垃圾回收”
垃圾: GC把程序中不用的内存空间视为垃圾。

1.1 GC所做的两件事:

  1. 找到内存空间里的垃圾
  2. 回收垃圾,让程序能再次利用这部分空间

满足以上两项功能的程序就是GC

1.2 没有GC会导致哪些问题?

  1. 内存泄漏:内存空间使用完毕后未释放。手动进行内存管理时,如果忘记释放内存空间,会发生内存泄漏,最终导致内存被占满。
  2. 垂悬指针(dangling pointer):指向曾经的对象,但是该对象已经不再存在。
int *p = NULL;
void fun() {
  int i = 10;
  p = &I;
}
int main() {
  fun();
  printf("\n*p = %d", *p); // *p = 10
  printf("\n*p = %d", *p); // 临时变量i已经销毁,*p = 1774530512
  return 0;
}
  1. 错误释放了使用中的内存空间。

1.3 GC 历史:

  • GC标记-清除算法(mark-sweep):

    John McCarthy身为Lisp之父和人工智能之父,是一名非常有名的黑客,事实上他同时也是GC之父。1960年,McCarthy在其论文 中首次发布了GC算法。

  • 引用计数法:

    1960年,George E. Collins在论文中发布了叫作引用计数的GC算法。当时Collins可能没有注意到,引用计数法有个缺点,就是它不能回收“循环引用”。Harold McBeth 在1963年指出了这个缺点。

  • GC复制算法:

    1963年,也有“人工智能之父”之称的Marvin L. Minsky在论文[7]中发布了复制算法。

目前为止发布的所有GC算法都只是以上三种算法的组合。

2.算法相关概念

2.1 对象/头/域

对象:GC世界中,对象表示“通过应用程序利用的数据集合”。(与面向对象编程中表示“具有属性和行为的事物”概念不同)。

对象配置在内存空间里。GC根据情况将配置好对象进行移动或销毁操作。因此对象是GC的基本单位。对象由头(head)域(field)构成。

对象

2.1.2 头

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

  • 对象的大小
  • 对象的种类

通过头来判别内存中存储的对象的边界。

2.1.3 域

对象使用者在对象中可访问的部分。类似于C中结构体的成员。对象使用者会引用或替换对象的域值。另一方面,对象使用者基本无法直接更改头的信息。

域中数据类型分为以下两种:

  • 指针
  • 非指针 (值本身:数值、字符及布尔)

对象内部,头之后存在1个及1个以上的域。

2.2 指针

GC 根据对象的指针去搜寻其他对象。GC对非指针不进行任何操。

注意点:
1.语言处理程序是否能判别指针和非指针。
2.指针指向对象的哪个部分。大多数语言处理程序中,指针都默认指向对象首地址。如果指针指向对象首地址以外的部分,GC就会变得非常复杂。

对象和指针

2.3 mutator

mutator "改变某物"的意思,主要是改变GC对象间的引用关系。其实体是“应用程序”,GC在mutator内部进行工作。

mutator实际进行的操作:

  • 生成对象
  • 更新指针

2.4 堆 Heap

动态(执行程序时)存放对象的内存空间。当mutator申请存放对象时,所需内存空间从这个堆中被分配给mutator。

GC是管理堆中已分配对象的机制。在开始执行mutator前,GC要分配用于堆的内存空间。一旦开始执行mutator,程序就会按照mutator的要求在堆中存放对象。等到堆被对象占满后,GC就会启动,从而分配可用空间。如果不能分配足够的可用空间,一般情况下我们就要扩大堆。

在《垃圾回收的算法与实现》一书“算法篇”中把堆的大小固定为常量HEAP_SIZE,不会进行扩大。此外,把$heap_start定为指向堆首地址的指针,把$heap_end定为指向堆末尾下一个地址的指针。也就是说,$heap_end等于$heap_start + HEAP_SIZE

2.5 活动对象

活动对象:分配到内存空间中能通过mutator引用的对象。
非活动对象:分配到内存空间中不能通过mutator引用的对象 (需要回收的垃圾)。

2.6 分配(allocation)

分配(allocation):在内存空间中分配对象。当mutator需要新对象时,向分配器申请一个大型合适的空间。
分配器(allocator):在堆的可用空间中寻找满足要求的空间,返回给mutator。

当堆被所有活动对象占满时,再也无法分配可用空间,此时有两种选择:

  1. 销毁至今为止的所有计算结果,输出错误信息。
  2. 扩大堆,分配可用空间。

2.6 分块(chunk)

分块在GC中指为利用对象而事先准备出来的空间。

初始状态下,堆被一个大的分块占据。然后根据mutator要求分割成合适大小的块,作为(活动)对象使用。活动对象转为垃圾被回收后,这部分被回收的内存空间再次成为分块,为下次被利用做准备。即内存中的各区块都重复着分块 --> 活动对象 --> 垃圾(非活动对象) --> 分块 ... 的过程

2.7 根 Root

GC中,根是指向对象指针的“起点”部分。能通过mutator直接引用的空间。

$obj= Object.new
$obj.field1 = Object.new
root

说明: 在这里$obj是全局变量。首先,我们在第1行分配一个对象(对象A),然后把$obj代入指向这个对象的指针。在第2行我们也分配一个对象(对象B),然后把$obj.field1代入指向这个对象的指针。在执行完第2行后,全局变量空间及堆如图所示。在这里我们可以使用$obj直接从伪代码中引用对象A,也就是说A是活动对象。此外,因为可以通过$obj经由对象A引用对象B,所以对象B也是活动对象。因此GC必须保护这些对象。

GC把上述这样可以直接或间接从全局变量空间中引用的对象视为活动对象。

与全局变量空间相同,我们也可以通过mutator直接引用调用栈(call stack)寄存器。也就是说,调用栈、寄存器以及全局变量空间都是根。

3.GC评价标准

3.1 评价GC算法性能的四个标准

  • 吞吐量
  • 最大暂停时间
  • 堆使用效率
  • 访问的局部性

3.1.1 吞吐量

单位时间内处理能力

mutator和GC执行示意图

如图,mutator执行过程中,GC启动3次,耗时分别为分别为A、B、C。则总耗时(A+B+C)。 假设堆大小为HEAP_SIZE,则吞吐量为HEAP_SIZE/ (A+B+C)

吞吐量也受到mutator动作影响。

当然,人们通常都喜欢吞吐量高的GC算法。然而判断各算法吞吐量的好坏时不能一概而论。打个比方,众所周知GC复制算法和GC标记-清除算法相比,活动对象越少吞吐量越高。这是因为GC复制算法只检查活动对象,而GC标记-清除算法则会检查所有的活动和非活动对象。然而,随着活动对象的增多,各GC算法表现出的吞吐量也会相应地变化。极端情况下,甚至会出现GC标记-清除算法比GC复制算法表现的吞吐量更高的情况。

3.1.2 最大暂停时间

指“因为执行GC而暂停执行mutator的最长时间”。(图1.7中最大暂停时间是B)

3.1.3 堆使用效率

影响因素:

  1. 头大小:
    在堆中堆放的信息越多,GC的效率也就越高,吞吐量也就随之得到改善。但毋庸置疑,头越小越好。因此为了执行GC,需要把在头中堆放的信息控制在最小限度。

  2. 堆的用法
    根据堆的用法,堆使用效率也会出现巨大的差异。举个例子,GC复制算法中将堆二等分,每次只使用一半,交替进行,因此总是只能利用堆的一半。相对而言,GC标记-清除算法和引用计数法就能利用整个堆。

堆使用效率和吞吐量以及最大暂停时间不可兼得。即:可用堆越大,GC运行越快;相反,越想有效利用有限的堆,GC花费时间越长。

3.1.3 访问的局部性

PC上四种存储器:寄存器、缓存、内存、辅助存储器(磁盘)。存取速度一般与存储容量成反比。

存储器分层

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

另一方面,具有引用关系的对象之间通常很可能存在连续访问的情况。这在多数程序中都很常见,称为“访问的局部性”。考虑到访问的局部性,把具有引用关系的对象安排在堆中较近的位 置,就能提高在缓存中读取到想利用的数据的概率,令mutator高速运行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容