为什么C ++没有垃圾回收器?

时间:2020-03-06 14:51:24  来源:igfitidea点击:

首先,因为垃圾收集的优点,所以我没有问这个问题。我提出这个问题的主要原因是,我确实知道Bjarne Stroustrup曾说过C ++将在某个时间点具有垃圾回收器。

话虽如此,为什么不添加呢?已经有一些C ++的垃圾收集器。这只是那些"说起来容易做起来难"的事情之一吗?还是有其他原因没有被添加(并且不会在C ++ 11中被添加)?

交叉链接:

  • C ++垃圾收集器

为了澄清起见,我理解C ++首次创建时没有垃圾收集器的原因。我想知道为什么不能添加收集器。

解决方案

哪种类型?是否应针对嵌入式洗衣机控制器,手机,工作站或者超级计算机进行优化?
它应该优先考虑gui响应性或者服务器加载吗?
应该使用大量内存还是大量CPU?

在很多不同的情况下都使用C / c ++。
我怀疑诸如boost智能指针之类的东西对于大多数用户来说就足够了

编辑自动垃圾收集器并不是性能问题(我们可以随时购买更多服务器),而只是性能的问题。
不知道GC何时启动,就像聘用了一名麻醉性航空公司飞行员一样,在大多数情况下,他们都很棒,但是当我们真正需要响应时!

可以添加隐式垃圾回收,但是并没有成功。可能不仅是由于实施方面的复杂性,还因为人们没有足够快地达成普遍共识。

Bjarne Stroustrup自己的话:

I had hoped that a garbage collector
  which could be optionally enabled
  would be part of C++0x, but there were
  enough technical problems that I have
  to make do with just a detailed
  specification of how such a collector
  integrates with the rest of the
  language, if provided. As is the case
  with essentially all C++0x features,
  an experimental implementation exists.

这里对此主题进行了很好的讨论。

总体概述:

C ++非常强大,可让我们做几乎所有事情。因此,它不会自动将很多可能影响性能的事情推到我们身上。垃圾回收可以通过智能指针轻松实现(智能对象包装带有引用计数的指针,当引用计数达到0时,这些对象会自动删除自身)。

C ++是在考虑没有垃圾收集的竞争对手的情况下构建的。与C和其他语言相比,效率是C ++不得不抵制批评的主要关注点。

垃圾收集有2种类型...

显式垃圾回收:

C ++ 0x将通过使用shared_ptr创建的指针进行垃圾回收

如果我们想要它,则可以使用它;如果我们不想要它,则不会被迫使用它。

如果我们不想等待C ++ 0x,则当前还可以使用boost:shared_ptr。

隐式垃圾回收:

它没有透明的垃圾收集器。不过,它将成为未来C ++规范的重点。

为什么Tr1没有隐式垃圾回收?

C ++ 0x的tr1应该有很多东西,Bjarne Stroustrup在之前的采访中指出,tr1并不如他所愿。

C ++背后的想法是,我们不会为不使用的功能付出任何性能影响。因此,添加垃圾回收将意味着让某些程序像C一样直接在硬件上运行,而某些程序则在某种类型的运行时虚拟机中运行。

没有什么可以阻止我们使用绑定到某些第三方垃圾收集机制的某种形式的智能指针。我似乎记得微软用COM做类似的事情,但进展并不顺利。

如果我们想要自动垃圾收集,那么有一些不错的C ++商业和公共领域垃圾收集器。对于适合垃圾回收的应用程序,C ++是一种出色的垃圾回收语言,其性能可与其他垃圾回收语言相比。有关C ++中自动垃圾收集的讨论,请参见《 C ++编程语言(第3版)》。另请参见Hans-J。 Boehm的C和C ++垃圾收集站点。
另外,C ++支持编程技术,该技术允许内存管理在没有垃圾回收器的情况下安全且隐式地进行。

资料来源:http://www.stroustrup.com/bs_faq.html#garbage-collection

至于为什么它没有内置它,如果我没记错的话,它是在GC出现之前就发明的,而且我不认为该语言可能有GC的原因有几个(IE与C的向后兼容性)

希望这可以帮助。

要回答有关C ++的大多数"为什么"问题,请阅读C ++的设计和演变。

C ++没有内置垃圾收集的最大原因之一是,让垃圾收集与析构函数很好地配合确实非常困难。据我所知,还没有人真正知道如何彻底解决它。有很多问题要处理:

  • 确定性对象的生存期(引用计数为我们提供了这一点,但是GC却没有。尽管可能没什么大不了的)。
  • 如果在垃圾回收对象时析构函数抛出该怎么办?大多数语言都忽略了此异常,因为实际上没有捕获块可以将其传输到该异常,但这对于C ++来说可能不是可接受的解决方案。
  • 如何启用/禁用它?自然地,这可能是编译时的决定,但是为GC编写的代码与为NOT GC编写的代码将有很大的不同,并且可能不兼容。我们如何调和这一点?

这些只是面临的一些问题。

在这里增加辩论。

垃圾回收存在一些已知问题,对它们的了解有助于理解C ++中为什么没有垃圾回收的问题。

1.性能?

第一个抱怨通常是关于性能的,但是大多数人并没有真正意识到他们在说什么。正如"马丁·贝克特(Martin Beckett)"所说明的那样,问题本身可能不是性能,而是性能的可预测性。

当前有2个广泛使用的GC系列:

  • 标记和扫描种类
  • 参考计数种类

"标记和扫描"速度更快(对整体性能的影响较小),但它遭受"冻结世界"综合症的困扰:即,当GC启动时,所有其他内容都将停止,直到GC进行清理为止。如果我们希望构建可以在几毫秒内响应的服务器...某些事务将无法达到期望:)

"引用计数"的问题有所不同:引用计数增加了开销,尤其是在多线程环境中,因为我们需要具有原子计数。此外,还有参考循环的问题,因此我们需要一个聪明的算法来检测并消除这些循环(通常也通过"冻结世界"来实现,尽管频率较低)。通常,到今天为止,这种方法(尽管通常响应速度更快,或者更经常地冻结)比"标记和扫描"方法要慢。

我看过埃菲尔铁塔实施者的一篇论文,他们试图实现一种"引用计数"垃圾收集器,而该类在不具有"冻结世界"方面具有与"标记并清除"类似的全局性能。它需要用于GC的单独线程(典型)。该算法有点令人恐惧(最后),但是论文很好地完成了一次介绍一个概念的过程,并展示了该算法从"简单"版本到成熟版本的演变。推荐阅读,只要我能把双手放回PDF文件上...

2.资源获取正在初始化

在C ++中,这是一个常见的习惯用法,我们会将资源的所有权包装在一个对象中,以确保正确释放它们。因为我们没有垃圾回收,所以它主要用于内存,但是在许多其他情况下它也很有用:

  • 锁(多线程,文件句柄,...)
  • 连接(到数据库,另一台服务器等)

这个想法是适当地控制对象的生存期:

  • 只要你需要它就应该还活着
  • 完成后应将其杀死

GC的问题是,如果它对前者有所帮助并最终保证在以后……这个"最终"值可能还不够。如果我们释放一个锁,那么我们真的希望它现在被释放,这样它就不会阻止任何进一步的呼叫!

使用GC的语言有两种解决方法:

  • 当堆栈分配足够时不要使用GC:通常是为了解决性能问题,但是在我们的情况下,这确实有用,因为范围定义了生命周期
  • using结构...,但是它是显式的(弱)RAII,而在C ++中,RAII是隐式的,因此用户不能不经意间就犯错误(通过省略using关键字)

3.智能指针

智能指针通常显示为处理" C ++"中的内存的灵丹妙药。我经常听到:由于我们拥有智能指针,因此我们毕竟不需要GC。

一个再错不过了。

智能指针确实有帮助:auto_ptrunique_ptr使用RAII概念,的确非常有用。它们是如此简单,我们可以很容易地自己编写它们。

但是,当需要共享所有权时,它将变得更加困难:我们可能会在多个线程之间共享,并且计数的处理存在一些细微的问题。因此,自然会走向" shared_ptr"。

太好了,毕竟这就是Boost的目的,但这不是万灵丹。实际上," shared_ptr"的主要问题在于它模拟了由"引用计数"实现的GC,但是我们需要自己全部实现循环检测... Urg

当然有这个" weak_ptr"问题,但是不幸的是我已经看到内存泄漏,尽管由于这些周期而使用了" shared_ptr" ...而且当我们处于多线程环境中时,这很难检测!

4.解决方案是什么?

没有万灵药,但与往常一样,这绝对是可行的。在没有GC的情况下,需要明确所有权:

  • 如果可能的话,宁愿在一个给定的时间只有一个所有者
  • 如果没有,请确保类图没有任何与所有权有关的循环,并通过微弱地应用weak_ptr来打破它们。

所以的确,拥有GC很棒。但是这不是小问题。同时,我们只需要卷起袖子即可。