共享指针(例如 boost::shared_ptr 或新的 std::shared_ptr)和垃圾回收方法(例如用 Java 或 C# 实现的方法)有什么区别?按照我的理解,共享指针会跟踪变量指向资源的次数,并在计数为零时自动销毁资源。然而,我的理解是垃圾收集器也管理内存资源,但需要额外的资源来确定一个对象是否仍在被引用,并不一定立即销毁资源。
我的假设是否正确,使用垃圾收集器和共享指针之间还有其他区别吗?另外,如果他们执行类似的任务但性能数据不同,为什么有人会在共享指针上使用垃圾收集器?
正如您所指出的,主要区别在于资源何时被释放/销毁。
GC 可能派上用场的一个优势是,如果您的资源需要很长时间才能释放。对于较短的程序生命周期,最好让资源悬空并在最后清理它们。如果达到资源限制,则 GC 可以采取行动释放其中一些资源。另一方面,共享指针会在引用计数为零时立即释放它们的资源。对于具有昂贵时间要求的资源的频繁获取-发布周期,这可能代价高昂。
另一方面,在某些垃圾收集实现中,垃圾收集要求整个程序在检查、移动和释放内存时暂停执行。有更智能的实现,但没有一个是完美的。
那些共享指针(通常称为引用计数)有循环的风险。
垃圾回收(Mark and Sweep)没有这个问题
在一个简单的垃圾收集系统中,没有人会持有指向任何对象的直接指针;相反,代码将保存对指向堆上对象的表条目的引用。堆上的每个对象都将存储它的大小(意味着所有堆对象将形成一个单链表)和一个指向保存它(或至少用于保存它)的对象表中对象的反向引用。
当堆或对象表变满时,系统将在表中的每个对象上设置一个“删除我”标志。它将检查它知道的每个对象,如果设置了“删除标志”,则取消设置并将它知道的所有对象添加到要检查的对象列表中。完成后,任何仍设置“删除我”标志的对象都可以删除。
一旦完成,系统将从堆的开头开始,获取存储在那里的每个对象,并查看它的对象引用是否仍然指向它。如果是这样,它将将该对象复制到堆的开头,或者刚好超过最后一个复制对象的末尾;否则该对象将被跳过(并可能在复制其他对象时被覆盖)。
在有垃圾收集器 (GC) 的语言中,GC 会跟踪并清理不再使用的内存,我们不需要考虑它。在大多数没有 GC 的语言中,我们有责任确定何时不再使用内存并调用代码来显式释放它,就像我们请求它一样。
更多详情:这里