如何在C ++中实现垃圾收集
我看到一些关于在C中实现GC的post,有人说这是不可能的,因为C是弱types的。 我想知道如何在C ++中实现GC。
我想知道如何做到这一点。 非常感谢你!
这是我朋友告诉我的彭博采访问题。 那个时候他做得很糟糕。 我们想知道你的想法。
C和C ++中的垃圾收集都是困难的主题,原因如下:
-
指针可以被转换为整数,反之亦然。 这意味着我可以有一个内存块只能通过一个整数,types转换为指针,然后解除引用。 一个垃圾收集器必须小心,不要认为块是无法到达的,当它仍然可以达到。
-
指针不是不透明的。 许多垃圾收集器,如停止和复制收集器,喜欢移动内存块或压缩它们以节省空间。 由于您可以明确地查看C和C ++中的指针值,因此难以正确实现。 您必须确定,如果某人正在使用类似于整数的方式进行一些棘手的操作,那么如果您移动了一块内存,则正确更新了整数。
-
内存pipe理可以明确完成。 任何垃圾收集器都需要考虑到用户可以随时显式释放内存块。
-
在C ++中,分配/取消分配和对象构造/销毁是分开的。 一块内存可以分配足够的空间来容纳一个对象,而不需要在那里实际构build任何对象。 一个好的垃圾回收器在回收内存时需要知道是否调用可能在那里分配的任何对象的析构函数。 对于标准库容器尤其如此,因为出于效率原因,通常使用
std::allocator
来使用这个技巧。 -
内存可以从不同的地方分配。 C和C ++可以通过内置的freestore(malloc / free或new / delete),也可以通过
mmap
或其他系统调用从OS获得内存,对于C ++,可以从get_temporary_buffer
或return_temporary_buffer
获得内存。 程序也可能从一些第三方库中获取内存。 一个好的垃圾收集器需要能够跟踪对这些其他池中的内存的引用,并且(可能)必须负责清理它们。 -
指针可以指向对象或数组的中间。 在像Java这样的垃圾收集语言中,对象引用总是指向对象的开始。 在C和C ++中,指针可以指向数组的中间,而在C ++中指向对象的中间(如果使用多重inheritance的话)。 这可能会使检测仍然可达的逻辑复杂化。
所以,简而言之,为C或C ++构build一个垃圾收集器是非常困难的。 大多数使用C和C ++进行垃圾回收的库在方法上都非常保守,在技术上是不健全的 – 例如,他们认为你不会拿一个指针,把它转换为一个整数,写入磁盘,然后加载它稍后再回来。 他们还假定内存中任何一个指针大小的值都可能是一个指针,所以有时候会拒绝释放无法访问的内存,因为有一个指向它的非零的机会。
正如其他人所指出的那样, Boehm GC确实为C和C ++做垃圾回收,但受上述限制。
有趣的是,C ++ 11包含了一些新的库函数,允许程序员在未来的垃圾收集工作中将内存区域标记为可达和不可达。 将来有可能用这种信息构build一个非常好的C ++ 11垃圾收集器。 与此同时,你需要非常小心,不要违反上述规定。
看看Boehm垃圾收集器 。
C不是C ++,但都有相同的“弱types”问题。 虽然这并不是隐含的types转换引起的问题,而是“捣乱”(颠覆types系统)的趋势,特别是在数据结构库中。
C和/或C ++有垃圾收集器。 博姆保守collections家可能是最好的知道。 这是保守的,如果它看起来像一个指向某个对象的位模式,它不会收集该对象。 这个价值可能完全是一些其他types的价值,所以可以收集对象,但“保守”意味着安全。
如果你使用计算的指针,即使是一个保守的收集器也可能被愚弄。 有一个数据结构,例如,每个列表节点都有一个字段,给出下一个节点地址和前一个节点地址之间的区别。 这个想法是为每个节点提供一个单链接的双链表行为,代价是更复杂的迭代器。 由于大多数节点没有明确的指针,因此可能会被错误地收集。
当然,这是一个非常特殊的情况。
更重要的是,你可以拥有可靠的析构函数或者垃圾收集,而不是两者。 收集垃圾周期时,收集器无法决定首先调用哪个析构函数。
由于RAII模式在C ++中普遍存在,并且依赖于析构函数,所以存在IMO冲突。 有可能是有效的例外,但我的观点是,如果你想要垃圾收集,你应该使用从垃圾回收(Java,C#,…)devise的语言。
你可以使用智能指针或创build自己的容器对象,将跟踪引用和处理内存分配等智能指针可能会更好。 通常,您可以完全避免dynamic堆分配。
例如:
char* pCharArray = new char[128]; // do some stuff with characters delete [] pCharArray;
如果在新的和删除你的删除之间有任何东西引发上述的危险将不会被执行。 上面的东西可以很容易地被更安全的“垃圾回收”代码所取代:
std::vector<char> charArray; // do some stuff with characters
从实际的编码angular度来看,彭博社的访谈问题毫不相干。 像大多数采访者一样,他们主要关心的是如何思考和沟通的技巧,而不是实际的解决scheme。
你看到的声明是错误的; Boehm收集器支持C和C ++。 我build议阅读Boehm收集器的文档(特别是这个页面 ),以便很好地概述如何用C或C ++编写垃圾收集器。
你可以阅读有关shared_ptr结构。
它实现了一个简单的引用计数垃圾收集器。
如果你想要一个真正的垃圾收集器,你可以重载新的操作符。
创build一个类似于shared_ptr的结构体,称之为Object。
这将包装创build的新对象。 现在重载它的操作符,可以控制GC。
你现在需要做的就是实现许多GCalgorithm之一