c++ - सी++ में कचरा कलेक्टर क्यों नहीं है?




garbage-collection c++11 (11)

Because these days, C++ doesn't need it anymore.

The situation, for code written these days (C++17 and following the official language Coding Guidelines ) is as follows:

  • Most memory ownership-related code is in libraries (especially those providing containers).
  • Most use of code involving memory ownership follows the RAII pattern , so allocation is made on construction and deallocation on destruction, which happens when exiting the scope in which something was allocated.
  • You do not explicitly allocate or deallocate memory directly .
  • Raw pointers do not own memory (if you've followed the guidelines), so you can't leak by passing them around.
  • If you're wondering how you're going to pass the starting addresses of sequences of values in memory - you'll be doing that with a span ; no raw pointer needed.
  • If you really need an owning "pointer", you use C++' standard-library smart pointers - they can't leak, and are quite efficient. Alternatively, you can pass ownership across scope boundaries with "owner pointers" . These are uncommon and must be used explicitly; and they allow for partial static checking against leaks.

"Oh yeah? But what about...

... if I just write code the way we've written C++ so far?"

Indeed, you could just disregard all of the guidelines and write leaky application code - and it will compile and run (and leak), same as always.

But it's not a "just don't do that" situation, where the developer is expected to be virtuous and exercise a lot of self control; it's just not simpler to write non-conforming code, nor is it faster to write, nor is it better-performing. Gradually it will also become more difficult to write, as you would face an increasing "impedance mismatch" with what conforming code provides and expects.

... if I reintrepret_cast ? Or do pointer arithmetic? Or other such hacks?"

Indeed, if you put your mind to it, you can write code that messes things up despite playing nice with the guidelines. परंतु:

  1. You would do this rarely (in terms of places in the code, not necessarily in terms of fraction of execution time)
  2. You would only do this intentionally, not accidentally
  3. Doing so will stand out in a codebase conforming to the guidelines
  4. It's the kind of code in which you would bypass the GC in another language anyway

... library development?"

If you're a C++ library developer then you do write unsafe code involving raw pointers, and you are required to code carefully and responsibly - but these are self-contained pieces of code written by experts.


so, bottom line: There's really no motivation to collect garbage generally, as you all but make sure not to produce garbage. GC is on the way to becoming a non-problem with C++.

That is not to say GC isn't an interesting problem for certain specific applications, when you want to employ custom allocation and de-allocations strategies. For those you would want custom allocation and de-allocation, not a language-level GC.

मैं इस सवाल से पहले कचरा संग्रह की योग्यता के कारण नहीं पूछ रहा हूं। यह पूछने का मेरा मुख्य कारण यह है कि मुझे पता है कि बजेर्न स्ट्राउस्ट्रप ने कहा है कि सी ++ में कुछ समय पर कचरा कलेक्टर होगा।

इसके साथ कहा, यह क्यों नहीं जोड़ा गया है? सी ++ के लिए पहले से ही कुछ कचरा कलेक्टर हैं। क्या यह सिर्फ उन लोगों में से एक है "काम करने से आसान कहा जाता है" चीजें टाइप करें? या ऐसे अन्य कारण हैं जिन्हें इसे जोड़ा नहीं गया है (और सी ++ 11 में नहीं जोड़ा जाएगा)?

क्रॉस लिंक:

बस स्पष्ट करने के लिए, मैं कारणों को समझता हूं कि सी ++ में कचरा कलेक्टर नहीं था जब इसे पहली बार बनाया गया था। मैं सोच रहा हूं कि कलेक्टर को क्यों जोड़ा नहीं जा सकता है।


किस प्रकार का? इसे एम्बेडेड वाशिंग मशीन नियंत्रकों, सेल फोन, वर्कस्टेशन या सुपरकंप्यूटर के लिए अनुकूलित किया जाना चाहिए?
क्या इसे गुई प्रतिक्रिया या सर्वर लोडिंग को प्राथमिकता देना चाहिए?
क्या यह बहुत सारी मेमोरी या सीपीयू के बहुत सारे उपयोग करना चाहिए?

सी / सी ++ का प्रयोग बहुत ही अलग परिस्थितियों में किया जाता है। मुझे संदेह है कि स्मार्ट पॉइंटर्स को बढ़ावा देने की तरह कुछ उपयोगकर्ताओं के लिए पर्याप्त होगा

संपादित करें - स्वचालित कचरा कलेक्टर प्रदर्शन की कोई समस्या नहीं है (आप हमेशा अधिक सर्वर खरीद सकते हैं) यह अनुमानित प्रदर्शन का सवाल है।
यह नहीं जानना कि जीसी कब लात मार रहा है, वह एक नार्कोलेप्टिक एयरलाइन पायलट को नियोजित करने जैसा है, ज्यादातर समय वे महान होते हैं - लेकिन जब आपको वास्तव में प्रतिक्रिया की आवश्यकता होती है!


यदि आप स्वचालित कचरा संग्रह चाहते हैं, तो सी ++ के लिए अच्छे वाणिज्यिक और सार्वजनिक-डोमेन कचरा कलेक्टर हैं। उन अनुप्रयोगों के लिए जहां कचरा संग्रह उपयुक्त है, सी ++ एक उत्कृष्ट कचरा एकत्रित भाषा है जो एक प्रदर्शन के साथ है जो एकत्रित अन्य कचरा एकत्रित भाषाओं के साथ तुलना करता है। C ++ में स्वचालित कचरा संग्रह की चर्चा के लिए सी ++ प्रोग्रामिंग भाषा (तृतीय संस्करण) देखें। हंस-जे भी देखें। सी और सी ++ कचरा संग्रह के लिए बोहेम की साइट। इसके अलावा, सी ++ प्रोग्रामिंग तकनीकों का समर्थन करता है जो मेमोरी प्रबंधन को कचरा कलेक्टर के बिना सुरक्षित और निहित होने की अनुमति देता है।

स्रोत: http://www.stroustrup.com/bs_faq.html#garbage-collection

इसके कारण यह क्यों नहीं बनाया गया है, अगर मुझे सही याद है तो जीसी की बात होने से पहले इसका आविष्कार किया गया था, और मुझे विश्वास नहीं है कि भाषा कई कारणों से जीसी हो सकती है (सी के साथ आईई पिछड़ा संगतता)

उम्मीद है की यह मदद करेगा।


यद्यपि यह एक पुराना सवाल है, फिर भी एक समस्या है कि मुझे किसी को भी संबोधित नहीं किया जाता है: कचरा संग्रह निर्दिष्ट करना लगभग असंभव है।

विशेष रूप से, C ++ मानक उस व्यवहार को प्राप्त करने के तरीके के बजाय बाहरी रूप से देखने योग्य व्यवहार के संदर्भ में भाषा निर्दिष्ट करने के लिए काफी सावधान है। कचरा संग्रह के मामले में, हालांकि, लगभग कोई बाहरी रूप से देखने योग्य व्यवहार नहीं है।

कचरा संग्रह का सामान्य विचार यह है कि यह सुनिश्चित करने के लिए उचित प्रयास करना चाहिए कि स्मृति आवंटन सफल होगा। दुर्भाग्यवश, यह गारंटी देना अनिवार्य रूप से असंभव है कि किसी भी स्मृति आवंटन सफल होगा, भले ही आपके पास ऑपरेशन में कचरा कलेक्टर हो। यह किसी भी मामले में कुछ हद तक सच है, लेकिन विशेष रूप से सी ++ के मामले में, क्योंकि यह (संभवतः) एक प्रतिलिपि कलेक्टर (या समान कुछ भी) का उपयोग करना संभव नहीं है जो संग्रह चक्र के दौरान वस्तुओं को स्मृति में स्थानांतरित करता है।

यदि आप वस्तुओं को स्थानांतरित नहीं कर सकते हैं, तो आप एक आवंटित स्मृति स्थान नहीं बना सकते जिससे आप अपने आवंटन कर सकते हैं - और इसका मतलब है कि आपका ढेर (या मुफ्त स्टोर, या जिसे आप इसे कॉल करना पसंद करते हैं) कर सकते हैं, और शायद , समय के साथ खंडित हो जाओ। बदले में, यह आवंटन को सफल होने से रोक सकता है, भले ही अनुरोध की जा रही राशि से अधिक स्मृति मुक्त हो।

हालांकि कुछ गारंटी के साथ आना संभव हो सकता है जो (संक्षेप में) कहता है कि यदि आप बार-बार आवंटन के समान पैटर्न को दोहराते हैं, और यह पहली बार सफल हुआ, तो यह बाद के पुनरावृत्तियों पर सफल रहेगा, बशर्ते आवंटित स्मृति पुनरावृत्तियों के बीच पहुंच से बाहर हो गया। यह इतनी कमजोर गारंटी है कि यह अनिवार्य रूप से बेकार है, लेकिन मुझे इसे मजबूत करने की कोई उचित आशा नहीं दिखाई दे रही है।

फिर भी, यह सी ++ के लिए प्रस्तावित किए गए प्रस्ताव से अधिक मजबूत है। पिछले प्रस्ताव [चेतावनी: पीडीएफ] (जो गिरा दिया गया) ने कुछ भी गारंटी नहीं दी थी। प्रस्ताव के 28 पृष्ठों में, बाहरी रूप से देखने योग्य व्यवहार के रास्ते में आपको जो मिला वह एक एकल (गैर-मानक) नोट था:

[नोट: कचरा एकत्रित कार्यक्रमों के लिए, एक उच्च गुणवत्ता वाले होस्टेड कार्यान्वयन को पुनः प्राप्त करने योग्य पहुंच की मात्रा को अधिकतम करने का प्रयास करना चाहिए। नोट नोट]

कम से कम मेरे लिए, यह निवेश पर वापसी के बारे में एक गंभीर सवाल उठाता है। हम मौजूदा कोड को तोड़ने जा रहे हैं (कोई भी निश्चित रूप से बिल्कुल कितना निश्चित नहीं है, लेकिन निश्चित रूप से काफी कुछ है), कार्यान्वयन और कोड पर नए प्रतिबंधों पर नई आवश्यकताओं को रखें, और बदले में हमें क्या मिल रहा है, बिल्कुल कुछ भी नहीं है?

यहां तक ​​कि सबसे अच्छा, हमें जो प्रोग्राम मिलते हैं वे जावा के साथ परीक्षण के आधार पर प्रोग्राम होते हैं, शायद उन्हें अब भी उतनी ही गति से चलाने के लिए लगभग छह गुना अधिक स्मृति की आवश्यकता होगी। इससे भी बदतर, कचरा संग्रह शुरुआत से जावा का हिस्सा था - सी ++ कचरा कलेक्टर पर पर्याप्त प्रतिबंध लगाता है कि लगभग निश्चित रूप से इससे भी बदतर लागत / लाभ अनुपात होगा (भले ही हम प्रस्ताव की गारंटी से परे जाएं और मान लें कि वहां होगा कुछ लाभ)।

मैं गणितीय स्थिति को सारांशित करता हूं: यह एक जटिल स्थिति है। जैसा कि कोई भी गणितज्ञ जानता है, एक जटिल संख्या में दो भाग होते हैं: असली और काल्पनिक। ऐसा लगता है कि हमारे यहां जो कुछ है वह वास्तविक हैं, लेकिन लाभ जो कम से कम अधिकतर (काल्पनिक) हैं।


लागू कचरा संग्रह जोड़ा जा सकता था, लेकिन यह सिर्फ कटौती नहीं किया था। शायद केवल कार्यान्वयन जटिलताओं के कारण ही नहीं, बल्कि लोगों के कारण सामान्य आम सहमति में तेजी से आने में सक्षम नहीं है।

Bjarne Stroustrup खुद से एक उद्धरण:

मैंने आशा की थी कि एक कचरा कलेक्टर जिसे वैकल्पिक रूप से सक्षम किया जा सकता है, सी ++ 0x का हिस्सा होगा, लेकिन पर्याप्त तकनीकी समस्याएं थीं जो मुझे केवल एक विस्तृत विनिर्देश के साथ करना है कि इस तरह के कलेक्टर बाकी भाषा के साथ कैसे एकीकृत होता है , अगर प्रदान किया गया है। जैसा कि अनिवार्य रूप से सभी सी ++ 0x विशेषताओं के मामले में है, एक प्रयोगात्मक कार्यान्वयन मौजूद है।

यहां विषय की अच्छी चर्चा here

सामान्य अवलोकन:

सी ++ बहुत शक्तिशाली है और आपको लगभग कुछ भी करने की अनुमति देता है। इस कारण से यह आपके लिए कई चीजों को स्वचालित रूप से धक्का नहीं देता है जो प्रदर्शन को प्रभावित कर सकता है। कचरा संग्रह आसानी से स्मार्ट पॉइंटर्स के साथ कार्यान्वित किया जा सकता है (ऑब्जेक्ट्स जो रेफरेंस गिनती के साथ प्वाइंटर्स को लपेटती हैं, जो संदर्भ गणना 0 तक पहुंच जाती है जब ऑटो स्वचालित रूप से हटाती है)।

सी ++ को प्रतियोगियों के साथ दिमाग में बनाया गया था जिसमें कचरा संग्रह नहीं था। दक्षता मुख्य चिंता थी कि सी ++ को सी और अन्य की तुलना में आलोचना को रोकना पड़ा।

कचरा संग्रह के 2 प्रकार हैं ...

स्पष्ट कचरा संग्रह:

C ++ 0x में shared_ptr के साथ बनाए गए पॉइंटर्स के माध्यम से कचरा संग्रह होगा

यदि आप इसे चाहते हैं तो आप इसका उपयोग कर सकते हैं, अगर आप इसे नहीं चाहते हैं तो आपको इसका उपयोग करने के लिए मजबूर नहीं किया जाता है।

आप वर्तमान में बूस्ट का उपयोग कर सकते हैं: shared_ptr साथ ही यदि आप C ++ 0x के लिए प्रतीक्षा नहीं करना चाहते हैं।

लागू कचरा संग्रह:

हालांकि इसमें पारदर्शी कचरा संग्रह नहीं है। यह भविष्य में सी ++ चश्मा के लिए एक फोकस बिंदु होगा हालांकि।

क्यों Tr1 में अंतर्निहित कचरा संग्रह नहीं है?

ऐसी कई चीजें हैं जो सी ++ 0x की टी 1 होनी चाहिए थीं, पिछले साक्षात्कारों में बजेर्न स्ट्राउस्ट्रप ने कहा था कि टी 1 में उतना ही नहीं था जितना वह पसंद करेंगे।


सी ++ कचरा संग्रह में निर्मित नहीं होने वाले सबसे बड़े कारणों में से एक यह है कि विनाशकों के साथ अच्छा खेलने के लिए कचरा संग्रह प्राप्त करना वाकई मुश्किल है। जहां तक ​​मुझे पता है, कोई भी वास्तव में जानता है कि इसे पूरी तरह से कैसे हल किया जाए। इससे निपटने के लिए बहुत सारे मुद्दे हैं:

  • वस्तुओं की निर्धारिती जीवनकाल (संदर्भ गिनती आपको यह देती है, लेकिन जीसी नहीं करता है। हालांकि यह एक सौदा का बड़ा नहीं हो सकता है)।
  • क्या होता है जब वस्तु को कचरा इकट्ठा किया जाता है जब एक विनाशक फेंकता है? अधिकांश भाषाएं इस अपवाद को अनदेखा करती हैं, क्योंकि वास्तव में इसे पकड़ने में सक्षम होने के लिए वास्तव में कोई पकड़ ब्लॉक नहीं है, लेकिन यह शायद सी ++ के लिए स्वीकार्य समाधान नहीं है।
  • इसे सक्षम / अक्षम कैसे करें? स्वाभाविक रूप से यह शायद संकलन समय का निर्णय होगा लेकिन जीसी बनाम कोड के लिए लिखा गया कोड जो जीसी के लिए लिखा गया है वह बहुत अलग और संभवतः असंगत नहीं होगा। आप इसे कैसे सुलझाते हैं?

ये केवल कुछ समस्याएं हैं।



स्ट्राउस्ट्रप ने 2013 में मूल सम्मेलन में कुछ अच्छी टिप्पणियां कीं।

इस वीडियो में बस 25m50s पर जाएं। (मैं वास्तव में पूरे वीडियो को देखने की सिफारिश करता हूं, लेकिन यह कचरा संग्रह के बारे में सामान को छोड़ देता है।)

जब आपके पास वास्तव में एक महान भाषा है जो वस्तुओं और मूल्यों को सीधे तरीके से निपटने के लिए आसान (और सुरक्षित, और अनुमानित, और आसानी से पढ़ा जा सकता है, और आसानी से पढ़ाया जाता है), जिससे (स्पष्ट) उपयोग से परहेज किया जाता है ढेर, तो आप कचरा संग्रह भी नहीं चाहते हैं

आधुनिक सी ++ के साथ, और सी ++ 11 में हमारे पास मौजूद सामान, सीमित परिस्थितियों को छोड़कर कचरा संग्रह अब वांछनीय नहीं है। वास्तव में, यहां तक ​​कि यदि एक अच्छा कचरा कलेक्टर प्रमुख सी ++ कंपाइलरों में से एक में बनाया गया है, तो मुझे लगता है कि इसका उपयोग अक्सर नहीं किया जाएगा। जीसी से बचने के लिए यह आसान नहीं होगा, कठिन नहीं होगा।

वह इस उदाहरण को दिखाता है:

void f(int n, int x) {
    Gadget *p = new Gadget{n};
    if(x<100) throw SomeException{};
    if(x<200) return;
    delete p;
}

यह सी ++ में असुरक्षित है। लेकिन यह जावा में भी असुरक्षित है! सी ++ में, यदि फ़ंक्शन जल्दी लौटाता है, तो delete कभी नहीं कहा जाएगा। लेकिन अगर आपके पास जावा में पूर्ण कचरा संग्रह था, तो आपको केवल एक सुझाव मिलता है कि वस्तु "भविष्य में किसी बिंदु पर" नष्ट हो जाएगी ( अपडेट: यह इससे भी बदतर है। जावा कभी भी फाइनलाइज़र को कॉल करने का वादा नहीं करता है - शायद इसे कभी नहीं कहा जा सकता है)। गैजेट में खुले फ़ाइल हैंडल, या डेटाबेस से कनेक्शन, या डेटा जिसे आपने बाद में किसी डेटाबेस पर लिखने के लिए buffered किया है, यह पर्याप्त नहीं है। हम जितनी जल्दी हो सके इन संसाधनों को मुक्त करने के लिए, गैजेट को समाप्त होने के तुरंत बाद नष्ट करना चाहते हैं। आप नहीं चाहते हैं कि आपका डेटाबेस सर्वर हजारों डेटाबेस कनेक्शनों के साथ संघर्ष कर रहा हो, जिनकी अब आवश्यकता नहीं है - यह नहीं पता कि आपका प्रोग्राम काम खत्म हो गया है।

तो समाधान क्या है? कुछ दृष्टिकोण हैं। स्पष्ट दृष्टिकोण, जिसका उपयोग आप अपनी वस्तुओं के विशाल बहुमत के लिए करेंगे:

void f(int n, int x) {
    Gadget p = {n};  // Just leave it on the stack (where it belongs!)
    if(x<100) throw SomeException{};
    if(x<200) return;
}

टाइप करने के लिए यह कम अक्षर लेता है। इस रास्ते में new नहीं हो रहा है। Gadget दो बार टाइप करने की आवश्यकता नहीं है। कार्य के अंत में वस्तु नष्ट हो जाती है। यदि आप यही चाहते हैं, तो यह बहुत सहज है। Gadget int या double के समान व्यवहार करता है। अनुमानित, पढ़ने में आसान, आसानी से पढ़ाने के लिए। सब कुछ एक 'मूल्य' है। कभी-कभी एक बड़ा मूल्य, लेकिन मूल्यों को पढ़ाना आसान होता है क्योंकि आपके पास 'दूरी पर कार्रवाई' नहीं होती है जिसे आप पॉइंटर्स (या संदर्भ) के साथ प्राप्त करते हैं।

आपके द्वारा बनाई जाने वाली अधिकांश वस्तुएं केवल उस फ़ंक्शन में उपयोग के लिए होती हैं जो उन्हें बनाई गई है, और शायद बाल कार्यों में इनपुट के रूप में पास की जाती है। ऑब्जेक्ट्स लौटने पर प्रोग्रामर को 'मेमोरी मैनेजमेंट' के बारे में सोचना नहीं चाहिए, या अन्यथा सॉफ्टवेयर के व्यापक रूप से अलग हिस्सों में वस्तुओं को साझा करना नहीं चाहिए।

दायरा और जीवनकाल महत्वपूर्ण हैं। अधिकांश समय, जीवन भर दायरे के समान ही आसान होता है। समझना आसान और सिखाना आसान है। जब आप एक अलग जीवनकाल चाहते हैं, तो उदाहरण के लिए shared_ptr उपयोग से, यह कोड को स्पष्ट रूप से पढ़ना चाहिए। (या मूल्य से बड़ी (बड़ी) वस्तुएं लौटाना, चाल-अर्थशास्त्र या unique_ptr लाभ unique_ptr

यह एक दक्षता समस्या की तरह प्रतीत हो सकता है। अगर मैं foo() से गैजेट वापस करना चाहता हूं तो क्या होगा? सी ++ 11 के चलते अर्थशास्त्र ने बड़ी वस्तुओं को वापस करना आसान बना दिया है। बस Gadget foo() { ... } लिखें और यह बस काम करेगा, और जल्दी से काम करेगा। आपको अपने आप को गड़बड़ करने की ज़रूरत नहीं है, केवल मूल्यों से मूल्य वापस करें और भाषा अक्सर आवश्यक अनुकूलन करने में सक्षम होगी। (सी ++ 03 से पहले भी, अनावश्यक प्रतिलिपि से बचने के लिए कंपाइलर्स ने उल्लेखनीय रूप से अच्छी नौकरी की थी।)

जैसा कि स्ट्रॉस्ट्रप ने वीडियो में कहीं और कहा (पैराफ्रेशिंग): "केवल एक कंप्यूटर वैज्ञानिक वस्तु को कॉपी करने और फिर मूल को नष्ट करने पर जोर देगा। (दर्शक हंसते हैं)। ऑब्जेक्ट को सीधे नए स्थान पर क्यों नहीं ले जाते? यह इंसान है (कंप्यूटर वैज्ञानिक नहीं) उम्मीद करते हैं। "

जब आप किसी वस्तु की केवल एक प्रति की गारंटी दे सकते हैं, तो ऑब्जेक्ट के जीवनकाल को समझना बहुत आसान है। आप जो जीवनकाल नीति चाहते हैं उसे चुन सकते हैं, और यदि आप चाहें तो कचरा संग्रह वहां है। लेकिन जब आप अन्य दृष्टिकोणों के लाभों को समझते हैं, तो आप पाएंगे कि कचरा संग्रह आपकी वरीयताओं की सूची के नीचे है।

यदि यह आपके लिए काम नहीं करता है, तो आप unique_ptr उपयोग कर सकते हैं, या unique_ptr विफल हो सकते हैं, shared_ptr । अच्छी तरह से लिखित सी ++ 11 स्मृति प्रबंधन की बात करते समय कई अन्य भाषाओं की तुलना में कम, आसान-पढ़ने-पढ़ने और आसान-से-सिखाना है।


Imposing garbage collection is really a low level to high level paradigm shift.

If you look at the way strings are handled in a language with garbage collection, you will find they ONLY allow high level string manipulation functions and do not allow binary access to the strings. Simply put, all string functions first check the pointers to see where the string is, even if you are only drawing out a byte. So if you are doing a loop that processes each byte in a string in a language with garbage collection, it must compute the base location plus offset for each iteration, because it cannot know when the string has moved. Then you have to think about heaps, stacks, threads, etc etc.


Mainly for two reasons:

  1. Because it doesn't need one (IMHO)
  2. Because it's pretty much incompatible with RAII, which is the cornerstone of C++

C++ already offers manual memory management, stack allocation, RAII, containers, automatic pointers, smart pointers... That should be enough. Garbage collectors are for lazy programmers who don't want to spend 5 minutes thinking about who should own which objects or when should resources be freed. That's not how we do things in C++.


When you compare C++ with Java, you can see immediately that C++ was not designed with implicit Garbage Collection in mind, while Java was.

Having things like arbitrary pointers in C-Style and deterministic destructors does not only slow down the performance of GC-implementations, it would also destroy backward compatibility for a large amount of C++-legacy-code.

In addition to that, C++ is a language that is intended to run as standalone executable instead of having a complex run-time environment.

All in all: Yes it would be possible to add Garbage Collection to C++, but for the sake of continuity it is better not to do so. The cost of doing so would be greater than the benefit.





c++11