C++垃圾回收機制

非託管C++

  1. C ++有垃圾收集,採用Hans-Boehm Garbage Collector的形式也可能有其他垃圾收集庫。
  2. 您可以使用使用RAII的智能指針(如果指針允許共享訪問,則使用引用計數)來確定何時刪除對象。一個好的智能指針庫是Boost的智能指針絕大多數情況下的智能指針可以取代原始指針。
  3. 一些應用程序框架(如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

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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章