C++垃圾回收机制

发布时间:2024年01月03日

非托管C++
C ++有垃圾收集,采用Hans-Boehm Garbage Collector的形式。也可能有其他垃圾收集库。
您可以使用使用RAII的智能指针(如果指针允许共享访问,则使用引用计数)来确定何时删除对象。一个好的智能指针库是Boost的智能指针。绝大多数情况下的智能指针可以取代原始指针。
一些应用程序框架(如Qt)构建对象树,以便框架的堆分配对象具有父子关系。因此,所有需要的是delete在一个对象上调用一个对象,并且它的所有子对象也将自动成为deleted。
托管c++
您可以通过两种方式使用.NET中的C ++:托管或非托管。在托管模式下,.NET的垃圾回收将代表您释放内存; 在非托管模式下,您接近C ++的正常/标准行为,因此您必须自己负责记忆。

使用公共语言运行时有许多优点,部分优点如下:
  (1)它使程序的性能得到了改进;
(2)能够轻松的使用其他语言开发的组件;
(3)支持语言功能,例如面向对象编程的继承、接口和重载;
(4)允许创建多线程的可放缩应用程序的显示自由线程处理支持;
(5)结构化异常处理支持;
(6)自定义特性支持;
(7)垃圾回收机制;
(8)使用委托取代函数指针,从而增强了类型安全和安全性。

总结

语言趋于同质化,语言趋于插件化。

摘抄:

真正的答案是,制作安全高效的垃圾收集机制的唯一方法是对不透明引用进行语言级别的支持。(或者相反,缺乏对直接内存操作的语言级支持。)

Java和C#可以做到这一点,因为它们有特殊的参考类型,不能被操纵。这使运行时可以自由地执行诸如在内存中移动分配的对象,这对于高性能的GC实现至关重要。

为了记录,没有现代的GC实现使用引用计数,所以这完全是一个红鲱鱼。现代GC使用世代收集,其中新分配的处理方式基本上与堆栈分配采用C ++语言相同,然后定期将任何新分配的仍处于活动状态的对象移动到单独的“幸存者”空间,并且整个一代的对象被立即释放。

这种方法有优点和缺点:好处在于,支持GC的语言的堆分配与不支持GC的语言的堆栈分配一样快,缺点是在销毁之前需要执行清理的对象需要一个单独的机制(例如C#的using关键字),否则他们的清理代码将不确定地运行。

请注意,高性能GC的一个关键是必须为特定类别的参考提供语言支持。C没有这种语言支持,永远不会; 因为C ++有运算符重载,它可以模拟一个GC'd指针类型,尽管它必须小心翼翼地完成。事实上,当微软发明了可以在CLR(.NET运行时)下运行的C ++方言时,他们必须为“C#风格的引用”(例如Foo^)发明新的语法,以将它们与“C ++风格的引用” (例如Foo&)。

C ++的确有什么,而C ++程序员经常使用的是智能指针,它实际上只是一个引用计数机制。我不认为引用计数是“真正的”GC,但它确实提供了许多相同的好处,代价是比手动内存管理或真正的GC更慢的性能,但具有确定性破坏的优势。

在一天结束时,答案真的归结为语言设计功能。C做出了一个选择,C ++做出了一个选择,使其能够与C向后兼容,同时仍然提供足够适用于大多数目的的替代方案,并且Java和C#做出了与C不兼容的另一种选择,但也足够用于大多数目的。不幸的是,没有银弹,但熟悉不同的选择将有助于你选择正确的那个你正在试图建立的任何程序。

The real answer is that the only way to make a safe, efficient garbage collection mechanism is to have language-level support for opaque references. (Or, conversely, a lack of language-level support for direct memory manipulation.)

Java and C# can do it because they have special reference types that cannot be manipulated. This gives the runtime the freedom to do things like move allocated objects in memory, which is crucial to a high-performance GC implementation.

For the record, no modern GC implementation uses reference counting, so that is completely a red herring. Modern GCs use generational collection, where new allocations are treated essentially the same way that stack allocations are in a language like C++, and then periodically any newly allocated objects that are still alive are moved to a separate "survivor" space, and an entire generation of objects is deallocated at once.

This approach has pros and cons: the upside is that heap allocations in a language that supports GC are as fast as stack allocations in a language that doesn't support GC, and the downside is that objects that need to perform cleanup before being destroyed either require a separate mechanism (e.g. C#'s using keyword) or else their cleanup code runs non-deterministically.

Note that one key to a high-performance GC is that there must be language support for a special class of references. C doesn't have this language support and never will; because C++ has operator overloading, it could emulate a GC'd pointer type, although it would have to be done carefully. In fact, when Microsoft invented their dialect of C++ that would run under the CLR (the .NET runtime), they had to invent a new syntax for "C#-style references" (e.g. Foo^) to distinguish them from "C++-style references" (e.g. Foo&).

What C++ does have, and what is regularly used by C++ programmers, is smart pointers, which are really just a reference-counting mechanism. I wouldn't consider reference counting to be "true" GC, but it does provide many of the same benefits, at the cost of slower performance than either manual memory management or true GC, but with the advantage of deterministic destruction.

At the end of the day, the answer really boils down to a language design feature. C made one choice, C++ made a choice that enabled it to be backward-compatible with C while still providing alternatives that are good enough for most purposes, and Java and C# made a different choice that is incompatible with C but is also good enough for most purposes. Unfortunately, there is no silver bullet, but being familiar with the different choices out there will help you to pick the correct one for whatever program you're currently trying to build.

https://softwareengineering.stackexchange.com/questions/113177/why-do-languages-such-as-c-and-c-not-have-garbage-collection-while-java-does

参考:

https://stackoverflow.com/questions/1695042/is-garbage-collection-automatic-in-standard-c

https://msdn.microsoft.com/en-us/library/yk97tc08.aspx?f=255&MSPPError=-2147217396

https://baike.baidu.com/item/%E5%85%AC%E5%85%B1%E8%AF%AD%E8%A8%80%E8%BF%90%E8%A1%8C%E6%97%B6/4361434?fr=aladdin

31 down vote
The real answer is that the only way to make a safe, efficient garbage collection mechanism is to have language-level support for opaque references. (Or, conversely, a lack of language-level support for direct memory manipulation.)

Java and C# can do it because they have special reference types that cannot be manipulated. This gives the runtime the freedom to do things like move allocated objects in memory, which is crucial to a high-performance GC implementation.

For the record, no modern GC implementation uses reference counting, so that is completely a red herring. Modern GCs use generational collection, where new allocations are treated essentially the same way that stack allocations are in a language like C++, and then periodically any newly allocated objects that are still alive are moved to a separate "survivor" space, and an entire generation of objects is deallocated at once.

This approach has pros and cons: the upside is that heap allocations in a language that supports GC are as fast as stack allocations in a language that doesn't support GC, and the downside is that objects that need to perform cleanup before being destroyed either require a separate mechanism (e.g. C#'s using keyword) or else their cleanup code runs non-deterministically.

Note that one key to a high-performance GC is that there must be language support for a special class of references. C doesn't have this language support and never will; because C++ has operator overloading, it could emulate a GC'd pointer type, although it would have to be done carefully. In fact, when Microsoft invented their dialect of C++ that would run under the CLR (the .NET runtime), they had to invent a new syntax for "C#-style references" (e.g. Foo^) to distinguish them from "C++-style references" (e.g. Foo&).

What C++ does have, and what is regularly used by C++ programmers, is smart pointers, which are really just a reference-counting mechanism. I wouldn't consider reference counting to be "true" GC, but it does provide many of the same benefits, at the cost of slower performance than either manual memory management or true GC, but with the advantage of deterministic destruction.

At the end of the day, the answer really boils down to a language design feature. C made one choice, C++ made a choice that enabled it to be backward-compatible with C while still providing alternatives that are good enough for most purposes, and Java and C# made a different choice that is incompatible with C but is also good enough for most purposes. Unfortunately, there is no silver bullet, but being familiar with the different choices out there will help you to pick the correct one for whatever program you're currently trying to build.
————————————————
版权声明:本文为CSDN博主「fengmao31」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fengmao31/article/details/80170982

文章来源:https://blog.csdn.net/zunguitiancheng/article/details/135367715
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。