C++14记忆模型如何在内部工作以及它与培根的垃圾收集统一理论的比较

How C++14 memory model works internally and how it compares to Bacon's Unified Theory of Garbage Collection

本文关键字:比较 理论 模型 记忆 在内部 工作 C++14      更新时间:2023-10-16

阅读David Bacon的《垃圾收集统一理论》我发现他提到现代gc是跟踪和引用计数的混合体:

在结构上的相似性,我们发现在跟踪之间和引用计数一样,我们开始重新审视各种收集器架构来理解这些风格之间的相互作用收集。我们观察到,所有现实的垃圾收集器都在实际上是某种形式的跟踪和引用计数的混合。这解释了为什么优化的"跟踪收集器"和优化的"引用计数收集器"变得越来越相似:因为事实上,他们正在互相吸收对方的特点。

他提到的一件事是使用ZCT(零计数表)来跟踪从堆栈引用的对象。关于ARC经常提到的另一件事是:

  1. 它不是线程安全的,因为增量不是原子的
  2. 如果它是线程安全的,它比GC慢

我的问题:现代c++(11/14/17)与这些语句相比如何?c++的ARC是混合的,并且还使用了一些跟踪GC的元素,这是真的吗?我在网上找不到任何指向这一点的东西,但论文非常清楚地指出:

我们观察到所有现实的垃圾收集器都在实际上是某种形式的跟踪和引用计数的混合。

关于现代c++,这是真的吗?或者它不认为c++ ARC是一个"现实的垃圾收集器"?有些人可能会争辩说c++没有GC, c++没有跟踪GC,但ARC是一种GC方法,正如它在论文中所述:

跟踪和引用计数被一致地看作是完全不同的垃圾收集方法具有非常独特的性能特性。我们已经实现了高性能收集器的两种类型,并在过程中观察我们越优化它们,它们的表现就越相似它们似乎有共同的深层结构。

和也出现在不同的其他来源,如维基百科这里和这里

引用计数是垃圾收集的一种形式,每个对象对它的引用数进行计数。垃圾被识别通过使引用计数为零。对象的引用计数为创建对它的引用时递增,在创建引用时递减引用被销毁。当计数达到零时,对象的内存被回收

同时,也有针对GC分配/回收的现代c++ ARC的基准测试(注意:我不是要求进行一般比较,而是针对内存管理的特定比较)。

最后但并非最不重要的是,如果我正在开发一个单线程应用程序,在c++上使用自增/自减作为原子操作的优势是什么?有办法让它失效吗?

现代c++(11/14/17)与这些语句相比如何?

没有可比性。c++从来没有,现在也没有对不再被引用的对象进行任何类型的自动垃圾收集。

关于现代c++,这是真的吗?

不,这不是真的。c++没有垃圾回收

有些人可能会说c++没有GC,

这里没有参数。这是事实。在定义当前c++标准的1400多页技术规范中,您将找不到任何类型的垃圾收集实现的任何描述。它不在那里。我看了看。

c++没有跟踪GC,但是正如它所说的,ARC是一种GC方法在纸上:

你当然可以在c++中为你自己的类实现你自己的垃圾收集。但这并不能使它成为语言本身的一部分。

并且,不,std::shared_ptr等不是垃圾收集,即使它是引用计数的。提示:循环引用

将自增/自减操作作为原子操作的优势是什么c++上的操作?

它们没有继承自己的"优势",更不用说c++中的其他所有东西了。这就像在问"拥有一辆车的好处是什么"。对一些人来说,拥有一辆车使他们的生活更轻松。对另一些人来说,它根本没有任何好处。

类似地,原子引用计数在特定的用例中具有优势。对另一些人来说,它根本没有任何好处。

此处正确的问题应该是"在[特定用例]中,原子递增/递减与[某些替代方法]相比有什么优势?"

您正在讨论垃圾收集器,找到所描述的属性与c++行为之间的类比,然后争论使c++成为垃圾收集语言。

不是这样的。GC的这些属性并不是GC的充分定义,因此任何表现出这些属性的东西都必须是GC。


我们观察到,所有现实的垃圾收集器实际上都是某种形式的跟踪和引用计数的混合。

关于现代c++,这是真的吗?

c++ 没有垃圾收集器,所以这句话是不打算应用于它。

正如你似乎建议的那样,我们可以反向工作,并说c++堆栈在上面描述的意义上是它自己的ZCT,因此提供了非常有限的跟踪形式。但这实际上并不明显有用,因为它本质上是简并的情况。

类似地,RAII智能指针可以使用引用计数,所以我们可以认为我们同时拥有跟踪和ARC。同样,这也不清楚是否有帮助。

同时,也有针对GC分配/回收的现代c++ ARC的基准测试(注意:我不是要求进行一般比较,而是针对内存管理的特定比较)。

一般来说,这不是一个有意义的比较。

c++提供了为每个资源(包括但不限于内存)选择正确的管理方案的能力,在一个精细的粒度级别,完全控制布局,生命周期,初始化,缓存效果等。

如果你能费心去做所有这些事情,并且做得很好,你就会在至少其中一些事情是相关的情况下获得更好的程序性能。

如果你不愿意做这些事情,或者你的程序不受它们的影响,你可以用更少的编程工作从通用GC中获得更好的性能。

唯一的方法是进行基准测试,您必须用不同的语言编写两次相同的程序,确保每个实现都针对语言功能进行了良好的优化,然后才能有意义地这样做。

单线程应用…自增/自减作为原子操作

在这种情况下可能没有任何好处,除非您正在处理中断,并且需要它们与正常代码之间的一致性。

在构建单线程应用程序时,你的平台是否真的发出了相关的fence/barriers/lock前缀/CAS等,这是一个实现质量问题。