关于C ++中垃圾收集的标记扫描(懒惰方法)?

时间:2011-03-04 05:21:15

标签: c++ garbage-collection mark-and-sweep

我知道参考计数器技术,但直到今天才阅读名为“编程语言概念”的书,从未听说过标记扫描技术。
根据这本书:

  

垃圾收集的原始标记扫描过程操作如下:运行时系统根据请求分配存储单元,并根据需要断开与单元的指针连接,而不考虑存储回收(允许垃圾累积),直到它已分配所有可用的细胞。此时,开始标记扫描过程以收集堆中剩余的所有垃圾。为了促进该过程,每个堆单元都有一个额外的指示符位或字段,由收集算法使用。

根据我的有限理解,C ++库中的智能指针使用引用计数技术。我想知道C ++中有没有使用这种智能指针实现的库?由于这本书纯粹是理论上的,我无法想象实现是如何完成的。举例说明这个想法将是非常有价值的。如果我错了,请纠正我。

谢谢,

2 个答案:

答案 0 :(得分:1)

虽然他们现在可能已升级它,但Mozilla Firefox过去常常使用混合方法,在可能的情况下使用引用计数的智能指针,并行标记并清除垃圾收集器以清理参考周期。其他项目可能采用了这种方法,但我并不完全确定。

我可以看到C ++程序员避免这种类型的垃圾收集的主要原因是它意味着对象析构函数将异步运行。这意味着如果创建了任何保留在重要资源(如网络连接或物理硬件)上的对象,则无法保证及时进行清理。此外,如果构造函数要访问共享资源,则析构函数必须非常小心地使用适当的同步,而在单线程,直接引用计数解决方案中,这不是必需的。

这种方法的另一个复杂性是C ++允许对指针进行原始算术运算,这使得任何垃圾收集器的实现变得非常复杂。保守地解决这个问题是可能的(例如,看看Boehm GC),尽管这是建立这种系统的重大障碍。

答案 1 :(得分:1)

在C ++中使用垃圾收集有一个难点,那就是识别什么是指针,什么不是。

如果您可以调整编译器为每种对象类型提供此信息,那么您已经完成了,但如果您不能,那么您需要使用保守的方法:即扫描内存以搜索可能的任何模式看起来像一个指针。这里还存在“位填充”的困难,人们将位填充为指针(较高的位在64位中大部分未使用)或XOR两个不同的指针以“节省空间”。

现在,在C ++ 0x中,标准委员会引入了标准ABI来帮助实现垃圾收集。在n3225中,您可以在 20.9.11 Pointer safety [util.dynamic.safety] 中找到它。这假设人们将为他们的类型实现这些功能,当然:

void declare_reachable(void* p); // throw std::bad_alloc
template <typename T> T* undeclare_reachable(T* p) noexcept;

void declare_no_pointers(char* p, size_t n) noexcept;
void undeclare_no_pointers(char* p, size_t n) noexcept;

pointer_safety get_pointer_safety() noexcept;

实施后,它将授权您将任何垃圾收集方案(定义这些功能)插入您的应用程序。当然,当然需要一些工作来实际在任何需要的地方提供这些操作。一种解决方案可能是简单地覆盖newdelete,但它不考虑指针算术......

最后,有很多垃圾收集策略:参考计数(带循环检测算法)和Mark And Sweep是主要的不同系统,但它们有各种风格(分代或不分组,复制/压缩与否,... )。