mark(在mark-and-sweep中)函数如何追踪从根访问的对象集?

use*_*427 3 c c++ garbage-collection

我试图了解标记和清除算法在一段代码中实际上是如何工作的。

我知道每次我 malloc() 时,我的 malloc() 函数都会将内存地址添加到链表中吗?然后,当我想进行垃圾回收时,我调用 mark() 函数,该函数接收一个“根”对象,然后从那里标记所有可访问的内存地址。然后我调用sweep() 并释放所有未标记的内存地址。

我对什么是“根”对象以及标记函数如何决定可以从“根”对象访问哪些对象感到困惑。

我认为如果有人能够给我一个关于标记和清除算法如何在一段代码中工作的小例子,这真的会对我有帮助......没有找到。

谢谢你。

Jer*_*fin 5

通常有一个根,而不仅仅是一个根对象。根集基本上是所有全局变量和所有当前活动的局部变量(例如,当前在堆栈上的所有本地变量)。将垃圾收集添加到 C 或 C++ 的真正困难之一是可能无法检测到根集中的指针(例如,如果您将指针写入临时文件,垃圾收集器将不知道要查找该文件)它)。

弄清楚从那里可以到达什么意味着检查任何一个指针,并且它指向的被认为是可达的。如果它指向的东西包含一个或多个指针,它会递归地跟随这些指针,所以所有可以从它到达的东西也被认为是可达的。

使用“精确”垃圾收集器,您可以使用某种类型信息来告诉垃圾收集器什么是指针。例如,每个对象都可能包含一个类型标记来说明它是什么类型的对象。然后你有一个表来告诉 GC 哪里(如果有的话)那种类型的对象的哪些部分是指针。

使用“保守”垃圾收集器,您只需查看数据的内容,并假设如果某物可以是指针,那么它就是。您唯一关心的指针是那些进入垃圾收集堆的指针。为了便于讨论,让我们假设一个 64 位指针和一个 8 兆字节的 GC 堆。这意味着我们查看内存并找到可能是指向 GC 堆的指针的大约 800 万个值中的任何一个,并假设任何这样的值都是一个指针,因此堆中该地址处的任何内容都被认为是可访问的(并且如果是这样,我们会递归地查找其中可能是指针的任何内容)。

尽管最初听起来(对许多人而言)后者通常将一切视为可访问的,但它实际上在实际使用中效果出奇地好。但是,它确实禁止某些垃圾收集策略。特别是,任何涉及压缩堆的事情都意味着在移动对象时需要调整指向该对象的所有指针——为此,我们必须确定我们正在修改的确实是指向该对象的指针,不仅仅是一些整数(或字符串等),它碰巧有一个看起来可能是指针的值。