我听说自动回收垃圾对于 C 语言来说并不是最佳选择,这是真的吗?
为什么 C 语言没有实现垃圾回收机制呢?
我听说自动回收垃圾对于 C 语言来说并不是最佳选择,这是真的吗?
为什么 C 语言没有实现垃圾回收机制呢?
不要听那些声称“C语言过时了,所以没有垃圾回收机制”的人。GC存在一些无法克服的基本问题,使其与C语言不兼容。
最大的问题是准确的垃圾回收需要扫描内存并识别任何遇到的指针。一些高级语言将整数限制为不使用所有可用位,以便高位可以用于区分对象引用和整数。这些语言可能会将字符串(可能包含任意字节序列)存储在一个特殊的字符串区域中,以便它们不能与指针混淆,一切都很好。然而,C语言实现无法做到这一点,因为字节、较大的整数、指针和其他所有内容都可以存储在结构、联合或通过malloc返回的块的一部分中。
如果你抛弃准确性要求,并决定接受一些对象永远不被释放的情况,因为程序中的一些非指针数据具有与这些对象地址相同的位模式怎么办?现在假设你的程序从外部世界(网络/文件等)接收数据。只要我能够猜测足够多的指针并在我向你的程序提供的字符串中模拟它们,我就能让你的程序泄漏任意数量的内存,并最终耗尽内存。如果应用De Bruijn序列,这将变得更加容易。
除此之外,垃圾回收就是一件非常慢的事情。您可以找到数百个喜欢声称相反的学者,但这并不会改变现实。GC的性能问题可以分为3大类:
那些声称现在GC很快的人只是将其与错误的东西进行比较:分配和释放成千上万或数百万个对象的写得很糟糕的C和C++程序。是的,这些也会很慢,但至少以一种可以测量和修复的可预测方式缓慢。一个编写良好的C程序将花费如此少的时间在malloc
/free
中,以至于开销甚至无法测量。
垃圾回收已经被实现在C语言中(例如Boehm-Demers-Weiser collector)。由于当时硬件和系统的限制,C语言最初并没有被指定为包含GC的语言。
编辑(回答一些其他帖子中提出的指责):
为了使保守 GC 有明确定义,你基本上只需要对语言进行一个更改:声明任何使指针暂时“不可见”的行为都会导致未定义的行为。例如,在当前的 C 中,你可以将一个指针写入文件,覆盖内存中的指针,稍后将其读回,并且(假设先前是有效的)仍然访问其指向的数据。GC 不一定会“意识到”该指针的存在,因此它可能会将内存视为不再可访问,因此开放给收集,因此稍后的间接引用将无法“工作”。std::less<T>在指针完全独立的对象上提供有意义的(更重要的是一致的)结果。使用复制收集器/清道夫需要额外的工作才能满足此要求(但我相信这是可能的)。处理(例如)某人散列地址并期望一致的结果仍然更加困难。这通常是一个糟糕的主意,但仍然是可能的,并且应产生一致的结果。
C语言是在20世纪70年代早期发明的,用于编写操作系统和其他低级别的东西。当时垃圾收集器已经存在(例如早期版本的Smalltalk),但我怀疑它们能否胜任在这样一个轻量级环境中运行的任务,而且还需要处理非常低级别的缓冲区和指针的所有复杂性。
很抱歉,认为C语言没有垃圾回收是因为它太老或是为不同的硬件设计而来,这种说法有点可笑。
问为什么C语言没有垃圾回收而其他语言有,则有点像问“为什么锤子有钝头而斧头有尖头”?嗯,语言就是工具,不同的工具用于构建具有不同要求的不同程序。一些程序(例如设备驱动程序或操作系统内核)具有使其几乎不可能实现垃圾回收却仍满足需求的要求,因此需要一种像C这样的语言,所以C被创建出来了。
就像每个工具一样,它之所以是它的样子,是因为它所解决的问题迫使它成为那样。那些认为C是由于70年代创建或由于旧硬件而被强迫的人让它看起来完全是环境所造成的。如果这是真的,C语言就会随着70年代的结束而消失,但它仍然是一种流行的语言。
此外,垃圾回收非常难以干净地实现,而且需要某种运行时系统,但C语言是用于裸机运行的。
C语言是一种非常老的语言,缺乏现代语言的许多花哨功能。现在要添加垃圾收集功能将需要对该语言进行重大改进。通常情况下,任何想要对C语言进行这么多改变的人都会更愿意创建自己的语言。
向语言中添加自动垃圾收集功能通常会降低性能,或者导致垃圾收集在不可预见的时间发生。向C语言添加垃圾收集将导致其失去其中一个比较优势,即可用于需要实时或接近实时响应时间的系统级编程。
C是一种非常底层的语言。它是一种你可能会选择用来编写高级语言的语言,例如垃圾回收等。它很小而简单,恰好做你所要求的事情。
C++在C的基础上构建,并添加了更复杂/自动的内存管理(例如在对象超出范围时调用析构函数)。你可能会想为什么C++没有垃圾回收,如果是这样,请看看Stroustrup的解释:简而言之,人们希望以更直接的方式完成任务,并且真正需要它的人可以使用库(也可以在C中使用)。
我喜欢JWZ对C语言的看法。 :-)
C语言是“认为自己是一种语言的PDP-11汇编语言”。
因此,如果您考虑创建一个可移植的汇编程序,那么不带垃圾回收的C语言看起来完全正确,原因很简单,CPU没有“垃圾回收”指令。
(虽然到目前为止,大多数其他CPU指令都可以很好地使用C语言捕获,但某些指令不行,例如C语言对SIMD操作的表达能力不足。)
* 是的,我知道有些人会找到反例来证明我错了。但通常情况下...
Objective_C是在ANSI C的基础上添加了大约12个关键字和一个名为id的类型。它具有垃圾回收功能,使用引用计数。
C语言的优点(也是缺点)在于它小巧、简单、轻量级,非常适合嵌入式和系统应用。使用GC会增加开销,使其不再小巧简单。对于C语言来说,使用GC并不合适。问题就是这么简单。