5

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

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

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

谢谢,

4

2 回答 2

2

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

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

现在,在 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但它不考虑指针算术......

最后,垃圾收集有许多策略:引用计数(使用循环检测算法)和标记和扫描是主要的不同系统,但它们有多种风格(是否生成,是否复制/压缩,...)。

于 2011-03-04T07:42:17.453 回答
1

尽管他们现在可能已经对其进行了升级,但 Mozilla Firefox 曾经使用一种混合方法,在这种方法中,尽可能使用引用计数智能指针,并使用并行运行的标记和清除垃圾收集器来清理引用周期。其他项目可能已经采用了这种方法,尽管我不完全确定。

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

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

于 2011-03-04T05:40:37.377 回答