सवाल ढेर और ढेर क्या और कहाँ हैं?


प्रोग्रामिंग भाषा किताबें बताती हैं कि मूल्य प्रकारों पर बनाया गया है ढेर, और संदर्भ प्रकार पर बनाए जाते हैं ढेर, इन दो चीजों के बारे में बताए बिना। मैंने इसका स्पष्ट स्पष्टीकरण नहीं पढ़ा है। मैं समझता हूँ क्या ढेर है। परंतु,

  • वे कहां और क्या हैं (शारीरिक रूप से वास्तविक कंप्यूटर की स्मृति में)?
  • ओएस या भाषा रनटाइम द्वारा उन्हें किस हद तक नियंत्रित किया जाता है?
  • उनका दायरा क्या है?
  • उनमें से प्रत्येक का आकार क्या निर्धारित करता है?
  • क्या एक तेज बनाता है?

7126
2017-09-17 04:18


मूल


वास्तव में एक अच्छा स्पष्टीकरण यहां पाया जा सकता है एक ढेर और ढेर के बीच क्या अंतर है? - Songo
इसके अलावा (वास्तव में) अच्छा: codeproject.com/Articles/76153/... (ढेर / ढेर भाग) - Ben
अच्छी व्याख्या मिल सकती है यहाँ - Bharat
youtube.com/watch?v=clOUdVDDzIM&spfreload=5 - Selvamani
संबंधित, देखें स्टैक टकराव। स्टैक टकराव उपायों ने सिस्टम चर और व्यवहार जैसे कुछ पहलुओं को प्रभावित किया rlimit_stack। Red Hat भी देखें अंक 1463241 - jww


जवाब:


ढेर निष्पादन के धागे के लिए स्क्रैच स्पेस के रूप में अलग स्मृति सेट है। जब कोई फ़ंक्शन कहा जाता है, स्थानीय चर के लिए स्टैक के शीर्ष पर एक ब्लॉक आरक्षित होता है और कुछ बहीखाता डेटा। जब वह फ़ंक्शन वापस आता है, तो ब्लॉक अप्रयुक्त हो जाता है और अगली बार फ़ंक्शन कहलाता है। ढेर हमेशा एक एलआईएफओ (पहले में बाहर) आदेश में आरक्षित है; हाल ही में आरक्षित ब्लॉक हमेशा मुक्त होने वाला अगला ब्लॉक है। यह ढेर का ट्रैक रखने के लिए वास्तव में आसान बनाता है; ढेर से एक ब्लॉक को मुक्त करना एक सूचक को समायोजित करने से ज्यादा कुछ नहीं है।

ढेर गतिशील आवंटन के लिए स्मृति सेट अलग है। ढेर के विपरीत, ढेर से ब्लॉक के आवंटन और विध्वंस के लिए कोई लागू पैटर्न नहीं है; आप किसी भी समय एक ब्लॉक आवंटित कर सकते हैं और किसी भी समय इसे मुक्त कर सकते हैं। इससे किसी भी समय किसी भी समय ढेर के किन हिस्सों को आवंटित या मुक्त किया जाता है, यह ट्रैक रखने के लिए यह और अधिक जटिल बनाता है; विभिन्न उपयोग पैटर्न के लिए ढेर प्रदर्शन को ट्यून करने के लिए उपलब्ध कई कस्टम हीप आवंटक हैं।

प्रत्येक थ्रेड को ढेर हो जाता है, जबकि आमतौर पर एप्लिकेशन के लिए केवल एक ही ढेर होता है (हालांकि विभिन्न प्रकार के आवंटन के लिए एकाधिक ढेर होने के लिए असामान्य नहीं है)।

सीधे अपने प्रश्नों का उत्तर देने के लिए:

ओएस या भाषा रनटाइम द्वारा उन्हें किस हद तक नियंत्रित किया जाता है?

जब थ्रेड बनाया जाता है तो ओएस प्रत्येक सिस्टम-स्तरीय थ्रेड के लिए स्टैक आवंटित करता है। आम तौर पर एप्लिकेशन के लिए ढेर आवंटित करने के लिए ओएस को भाषा रनटाइम द्वारा बुलाया जाता है।

उनका दायरा क्या है?

ढेर एक धागे से जुड़ा हुआ है, इसलिए जब थ्रेड से बाहर निकलता है तो पुनः दावा किया जाता है। ढेर आमतौर पर रनटाइम द्वारा एप्लिकेशन स्टार्टअप पर आवंटित किया जाता है, और जब एप्लिकेशन (तकनीकी रूप से प्रक्रिया) निकलता है तो उसे पुनः दावा किया जाता है।

उनमें से प्रत्येक का आकार क्या निर्धारित करता है? 

स्टैक का आकार सेट होता है जब थ्रेड बनाया जाता है। ढेर का आकार एप्लिकेशन स्टार्टअप पर सेट किया गया है, लेकिन अंतरिक्ष की आवश्यकता होने पर बढ़ सकता है (आवंटक ऑपरेटिंग सिस्टम से अधिक मेमोरी का अनुरोध करता है)।

क्या एक तेज बनाता है?

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

एक स्पष्ट प्रदर्शन:
छवि स्रोत: vikashazrati.wordpress.com


5239
2017-09-17 04:52



अच्छा जवाब - लेकिन मुझे लगता है कि आपको यह जोड़ना चाहिए कि जब प्रक्रिया शुरू होती है (ओएस के अस्तित्व को मानते हुए) ओएस द्वारा स्टैक आवंटित किया जाता है, तो इसे प्रोग्राम द्वारा इनलाइन बनाए रखा जाता है। यह एक और कारण है कि ढेर तेज है, साथ ही - पुश और पॉप ऑपरेशंस आम तौर पर एक मशीन निर्देश होते हैं, और आधुनिक मशीनें उनमें से कम से कम 3 चक्र एक चक्र में कर सकती हैं, जबकि आवंटन या ढेर को मुक्त करने में ओएस कोड में कॉल करना शामिल है। - sqykly
मैं अंत में आरेख द्वारा वास्तव में उलझन में हूँ। मैंने सोचा कि जब तक मैंने उस छवि को नहीं देखा तब तक मुझे यह मिला। - Sina Madani
@ एनेरेल प्रोसेसर ओएस के साथ या उसके बिना निर्देश चलाता है। मेरे दिल के नजदीक एक उदाहरण एसएनईएस है, जिसमें कोई एपीआई कॉल नहीं था, ओएस नहीं, जैसा कि हम आज जानते हैं - लेकिन यह एक ढेर था। एक स्टैक पर आवंटित करना इन प्रणालियों पर अतिरिक्त और घटाव है और यह उन चरमों के लिए ठीक है जब उन्हें बनाए गए फ़ंक्शन से लौटकर पॉप किया जाता है, लेकिन एक कन्स्ट्रक्टर कहता है, जिसके परिणामस्वरूप न केवल परिणाम हो सकता है दूर फेंका। इसके लिए हमें ढेर की जरूरत है, जो कॉल और वापसी के लिए बंधी नहीं है। अधिकांश ओएस में एपीआई एक ढेर होता है, इसे स्वयं करने का कोई कारण नहीं है - sqykly
"ढेर मेमोरी सेट स्क्रैच स्पेस के रूप में अलग है"। ठंडा। लेकिन जावा मेमोरी संरचना के संदर्भ में वास्तव में यह "अलग" कहां है ?? क्या यह ढेर स्मृति / गैर-ढेर स्मृति / अन्य (जावा मेमोरी संरचना प्रति के अनुसार है betsol.com/2017/06/... ) - Jatin Shashoo


ढेर:

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

ढेर:

  • स्टैक की तरह कंप्यूटर रैम में संग्रहीत।
  • सी ++ में, ढेर पर चर को मैन्युअल रूप से नष्ट किया जाना चाहिए और कभी भी दायरे से बाहर नहीं होना चाहिए। डेटा से मुक्त है delete, delete[], या free
  • ढेर पर चर के तुलना में आवंटित करने के लिए धीमी गति से।
  • कार्यक्रम द्वारा उपयोग के लिए डेटा के ब्लॉक आवंटित करने की मांग पर प्रयुक्त।
  • बहुत सारे आवंटन और विध्वंस होने पर विखंडन हो सकता है।
  • सी ++ या सी में, ढेर पर बनाए गए डेटा को पॉइंटर्स द्वारा इंगित किया जाएगा और आवंटित किया जाएगा new या malloc क्रमशः।
  • अगर बफर के बहुत बड़े आवंटित किए जाने का अनुरोध किया जाता है तो आवंटन विफलता हो सकती है।
  • यदि आप नहीं जानते कि आपको रन समय पर कितना डेटा चाहिए या आपको बहुत सारे डेटा आवंटित करने की आवश्यकता है तो आप ढेर का उपयोग करेंगे।
  • स्मृति रिसाव के लिए जिम्मेदार।

उदाहरण:

int foo()
{
  char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack).
  bool b = true; // Allocated on the stack.
  if(b)
  {
    //Create 500 bytes on the stack
    char buffer[500];

    //Create 500 bytes on the heap
    pBuffer = new char[500];

   }//<-- buffer is deallocated here, pBuffer is not
}//<--- oops there's a memory leak, I should have called delete[] pBuffer;

2095
2017-09-17 04:20



पॉइंटर पीबीफर और बी का मान ढेर पर स्थित है, और अधिकांशतः फ़ंक्शन के प्रवेश द्वार पर आवंटित किया जाता है। कंपाइलर के आधार पर, फ़ंक्शन प्रवेश द्वार पर भी बफर आवंटित किया जा सकता है। - Andy
यह एक आम गलतफहमी है कि C भाषा, जैसा कि परिभाषित किया गया है C99 भाषा मानक (पर उपलब्ध है open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf ), एक "ढेर" की आवश्यकता है। वास्तव में, शब्द 'स्टैक' मानक में भी प्रकट नहीं होता है। यह कथन कथन का जवाब देता है Cस्टैक उपयोग सामान्य रूप से सच है, लेकिन भाषा द्वारा किसी भी तरह से आवश्यक नहीं है। देख knosof.co.uk/cbook/cbook.html अधिक जानकारी के लिए, और विशेष रूप से कैसे C जैसे विषम गेंद आर्किटेक्चर पर लागू किया गया है en.wikipedia.org/wiki/Burroughs_large_systems - johne
@ ब्रायन आपको समझा जाना चाहिए क्यूं कर बफर [] और पीबीफर पॉइंटर स्टैक पर बनाए जाते हैं और ढेर पर पीबीफर का डेटा क्यों बनाया जाता है। मुझे लगता है कि कुछ पीपीएल आपके उत्तर से भ्रमित हो सकते हैं क्योंकि उन्हें लगता है कि कार्यक्रम विशेष रूप से यह निर्देश दे रहा है कि स्मृति को ढेर बनाम ढेर पर आवंटित किया जाए लेकिन यह मामला नहीं है। क्या ऐसा इसलिए है क्योंकि बफर एक मूल्य प्रकार है जबकि पीबीफर एक संदर्भ प्रकार है? - Howiecamp
@ रिमूवर: कोई पॉइंटर कोई पता नहीं रखता है और यह ढेर या ढेर पर समान रूप से कुछ इंगित कर सकता है। नया, मॉलोक, और कुछ अन्य कार्य मॉलोक के समान ही ढेर पर आवंटित करते हैं और आवंटित स्मृति के पते को वापस कर देते हैं। आप ढेर पर आवंटित क्यों करना चाहते हैं? ताकि आपकी याददाश्त गुंजाइश से बाहर न जाए और जब तक आप इसे प्राप्त न करें तब तक रिहा कर दें। - Brian R. Bondy
"स्मृति रिसाव के लिए जिम्मेदार" - मेमोरी लीक के लिए ढेर जिम्मेदार नहीं हैं! आलसी / भूलभुलैया / पूर्व-जावा कोडर / कोडर जो बकवास नहीं देते हैं! - Laz


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

  • वस्तुओं के ढेर में, आइटम दूसरे के शीर्ष पर एक क्रम में बैठे क्रम में बैठते हैं, और आप केवल शीर्ष को हटा सकते हैं (पूरी चीज़ को ऊपर छोड़कर)।

    Stack like a stack of papers

    एक ढेर की सादगी यह है कि आपको आवंटित स्मृति के प्रत्येक खंड के रिकॉर्ड वाले तालिका को बनाए रखने की आवश्यकता नहीं है; आपको केवल एकमात्र राज्य की जानकारी है जो ढेर के अंत तक एक सूचक है। आवंटित करने और आवंटित करने के लिए, आप केवल उस सूचक को बढ़ाएं और घटाएं। नोट: स्मृति के एक वर्ग के शीर्ष पर शुरू करने के लिए कभी-कभी एक स्टैक को कार्यान्वित किया जा सकता है और ऊपर की ओर बढ़ने के बजाय नीचे का विस्तार किया जा सकता है।

  • एक ढेर में, वस्तुओं को रखने के तरीके के लिए कोई विशेष आदेश नहीं है। आप किसी भी क्रम में वस्तुओं तक पहुंच सकते हैं और हटा सकते हैं क्योंकि कोई स्पष्ट 'शीर्ष' आइटम नहीं है।

    Heap like a heap of licorice allsorts

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

इन छवियों को एक ढेर और ढेर में स्मृति आवंटित करने और मुक्त करने के दो तरीकों का वर्णन करने का एक अच्छा काम करना चाहिए। यम!

  • ओएस या भाषा रनटाइम द्वारा उन्हें किस हद तक नियंत्रित किया जाता है?

    जैसा कि बताया गया है, ढेर और ढेर सामान्य शब्द हैं, और कई तरीकों से कार्यान्वित किया जा सकता है। कंप्यूटर प्रोग्रामों में आमतौर पर एक स्टैक होता है जिसे ए कहा जाता है कॉल स्टैक जो मौजूदा फ़ंक्शन के लिए प्रासंगिक जानकारी संग्रहीत करता है जैसे पॉइंटर जिसे किसी भी फ़ंक्शन से कॉल किया गया था, और किसी भी स्थानीय चर। चूंकि फ़ंक्शंस अन्य फ़ंक्शंस को कॉल करता है और फिर वापस लौटाता है, तो स्टैक कॉल स्टैक के आगे फ़ंक्शंस से जानकारी रखने के लिए बढ़ता और घटता है। एक कार्यक्रम में वास्तव में रनटाइम नियंत्रण नहीं होता है; यह प्रोग्रामिंग भाषा, ओएस और यहां तक ​​कि सिस्टम आर्किटेक्चर द्वारा निर्धारित किया जाता है।

    एक ढेर एक सामान्य शब्द है जो किसी भी स्मृति के लिए उपयोग किया जाता है जिसे गतिशील और यादृच्छिक रूप से आवंटित किया जाता है; यानी आदेश से बाहर। स्मृति आवंटन एपीआई कार्यों को आवंटित करने के लिए आम तौर पर ओएस द्वारा आवंटित किया जाता है। गतिशील रूप से आवंटित स्मृति प्रबंधन में आवश्यक ओवरहेड का एक उचित हिस्सा है, जिसे आमतौर पर ओएस द्वारा नियंत्रित किया जाता है।

  • उनका दायरा क्या है?

    कॉल स्टैक इतनी निम्न स्तर की अवधारणा है कि यह प्रोग्रामिंग की भावना में 'स्कोप' से संबंधित नहीं है। यदि आप कुछ कोड को अलग करते हैं तो आपको स्टैक के हिस्सों के सापेक्ष सूचक शैली संदर्भ दिखाई देंगे, लेकिन जहां तक ​​उच्च स्तर की भाषा का संबंध है, भाषा अपनी दायरे के नियमों को लागू करती है। हालांकि, एक ढेर का एक महत्वपूर्ण पहलू यह है कि एक बार एक समारोह लौटने के बाद, उस समारोह के लिए स्थानीय कुछ भी तुरंत ढेर से मुक्त हो जाता है। यह काम करता है जिस तरह से आप यह काम करने की उम्मीद करेंगे कि आपकी प्रोग्रामिंग भाषाएं कैसे काम करती हैं। एक ढेर में, इसे परिभाषित करना भी मुश्किल है। दायरा ओएस द्वारा जो कुछ भी उजागर किया गया है, लेकिन आपकी प्रोग्रामिंग भाषा शायद आपके नियमों में "स्कोप" के बारे में अपने नियम जोड़ती है। प्रोसेसर आर्किटेक्चर और ओएस वर्चुअल एड्रेसिंग का उपयोग करते हैं, जो प्रोसेसर भौतिक पते पर अनुवाद करता है और पृष्ठ त्रुटियां हैं, आदि। वे ट्रैक करते हैं कि कौन से पेज किस एप्लिकेशन से संबंधित हैं। आपको इसके बारे में चिंता करने की ज़रूरत नहीं है, हालांकि, क्योंकि आप अपनी प्रोग्रामिंग भाषा आवंटित करने और मुफ्त मेमोरी के लिए उपयोग की जाने वाली किसी भी विधि का उपयोग करते हैं, और त्रुटियों की जांच करें (यदि किसी भी कारण से आवंटन / मुक्त करने में विफल रहता है)।

  • उनमें से प्रत्येक का आकार क्या निर्धारित करता है?

    फिर, यह भाषा, कंपाइलर, ऑपरेटिंग सिस्टम और वास्तुकला पर निर्भर करता है। एक ढेर आमतौर पर पूर्व-आवंटित होता है, क्योंकि परिभाषा के अनुसार यह संगत स्मृति (अंतिम पैराग्राफ में उस पर अधिक होना चाहिए) होना चाहिए। भाषा संकलक या ओएस इसका आकार निर्धारित करता है। आप स्टैक पर डेटा के विशाल हिस्सों को स्टोर नहीं करते हैं, इसलिए यह इतना बड़ा होगा कि इसे कभी भी पूरी तरह से उपयोग नहीं किया जाना चाहिए, अवांछित अंतहीन रिकर्सन (इसलिए, "स्टैक ओवरफ़्लो") या अन्य असामान्य प्रोग्रामिंग निर्णयों के मामलों को छोड़कर।

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

  • क्या एक तेज बनाता है?

    ढेर तेज है क्योंकि सभी मुफ्त मेमोरी हमेशा संगत होती है। मुफ्त मेमोरी के सभी सेगमेंटों के लिए किसी भी सूची को बनाए रखने की आवश्यकता नहीं है, केवल स्टैक के वर्तमान शीर्ष पर एक पॉइंटर है। कंपाइलर आमतौर पर इस पॉइंटर को एक विशेष, तेज़ में स्टोर करते हैं रजिस्टर इस उद्देश्य के लिए। और भी, एक ढेर पर बाद के संचालन आमतौर पर स्मृति के बहुत पास के क्षेत्रों में केंद्रित होते हैं, जो बहुत कम स्तर पर प्रोसेसर ऑन-डाई कैश द्वारा अनुकूलन के लिए अच्छा होता है।


1261
2018-03-19 14:38



डेविड मैं इस बात से सहमत नहीं हूं कि यह एक अच्छी छवि है या "पुश-डाउन स्टैक" अवधारणा को चित्रित करने के लिए एक अच्छी अवधि है। जब आप स्टैक में कुछ जोड़ते हैं, तो स्टैक की अन्य सामग्री नहीं कर रहे हैं नीचे धकेल दिया, वे रहते हैं वे कहाँ हैं। - thomasrutter
इस जवाब में एक बड़ी गलती शामिल है। स्थिर चर को ढेर पर आवंटित नहीं किया जाता है। मेरा जवाब देखें [लिंक] stackoverflow.com/a/13326916/1763801 स्पष्टीकरण के लिए। आप "स्थैतिक" चर के साथ "स्वचालित" चर के बराबर हैं, लेकिन वे बिल्कुल समान नहीं हैं - davec
विशेष रूप से, आप कहते हैं कि "स्थिर रूप से आवंटित स्थानीय चर" स्टैक पर आवंटित किए जाते हैं। असल में वे डेटा सेगमेंट में आवंटित किए जाते हैं। केवल स्वचालित रूप से आवंटित चर (जिसमें अधिकांश स्थानीय चर शामिल नहीं हैं और संदर्भ के बजाए मान द्वारा पारित फ़ंक्शन पैरामीटर जैसी चीजें भी शामिल हैं) को स्टैक पर आवंटित किया जाता है। - davec
मैंने अभी महसूस किया है कि आप सही हैं - सी में, स्थैतिक आवंटन जो कुछ भी नहीं है उसके लिए एक शब्द की बजाय अपनी अलग चीज है गतिशील। मैंने अपना जवाब संपादित कर लिया है, धन्यवाद। - thomasrutter
यह सिर्फ सी जावा, पास्कल, पायथन और कई अन्य लोगों के पास स्थिर बनाम स्वचालित बनाम गतिशील आवंटन की धारणा नहीं है। "स्थैतिक आवंटन" का अर्थ केवल हर जगह के बारे में एक ही बात है। कोई भी भाषा में स्थिर आवंटन का अर्थ "गतिशील नहीं" होता है। आप जो वर्णन कर रहे हैं उसके लिए "स्वचालित" आवंटन शब्द चाहते हैं (यानी स्टैक पर चीजें)। - davec


(मैंने इस उत्तर को एक और प्रश्न से ले जाया है जो इस के एक या अधिक कम था।)

आपके प्रश्न का उत्तर कार्यान्वयन विशिष्ट है और संकलक और प्रोसेसर आर्किटेक्चर में भिन्न हो सकता है। हालांकि, यहां एक सरल व्याख्या है।

  • ढेर और ढेर दोनों अंतर्निहित ऑपरेटिंग सिस्टम से आवंटित स्मृति क्षेत्र हैं (अक्सर वर्चुअल मेमोरी जो मांग पर भौतिक स्मृति में मैप की जाती है)।
  • एक बहु थ्रेडेड वातावरण में प्रत्येक धागे का अपना पूरी तरह से स्वतंत्र ढेर होगा लेकिन वे ढेर साझा करेंगे। समवर्ती पहुंच को ढेर पर नियंत्रित किया जाना चाहिए और ढेर पर संभव नहीं है।

ढेर

  • ढेर में प्रयुक्त और नि: शुल्क ब्लॉक की एक लिंक्ड सूची होती है। ढेर पर नए आवंटन (द्वारा new या malloc) मुक्त ब्लॉक में से एक से एक उपयुक्त ब्लॉक बनाकर संतुष्ट हैं। इसके लिए ढेर पर ब्लॉक की सूची अद्यतन करने की आवश्यकता है। इस मेटा जानकारी ढेर पर ब्लॉक के बारे में भी अक्सर हर ब्लॉक के सामने एक छोटे से क्षेत्र में ढेर पर संग्रहीत किया जाता है।
  • चूंकि ढेर बढ़ता है नए ब्लॉक अक्सर निचले पतों से उच्च पते की ओर आवंटित किए जाते हैं। इस प्रकार आप ढेर के बारे में सोच सकते हैं ढेर स्मृति ब्लॉक के रूप में आकार में वृद्धि स्मृति स्मृति आवंटित किया जाता है। यदि ढेर आवंटन के लिए बहुत छोटा है, तो अंतर्निहित ऑपरेटिंग सिस्टम से अधिक स्मृति प्राप्त करके आकार को अक्सर बढ़ाया जा सकता है।
  • कई छोटे ब्लॉक आवंटित करने और हटाने से राज्य में ढेर निकल सकता है जहां उपयोग किए गए ब्लॉक के बीच बहुत सारे छोटे मुक्त ब्लॉक छेड़छाड़ किए जाते हैं। एक बड़ा ब्लॉक आवंटित करने का अनुरोध विफल हो सकता है क्योंकि नि: शुल्क ब्लॉक के संयुक्त आकार पर्याप्त होने के बावजूद आवंटन अनुरोध को पूरा करने के लिए कोई भी मुफ्त ब्लॉक पर्याप्त नहीं है। यह कहा जाता है ढेर विखंडन
  • जब एक मुक्त ब्लॉक के नजदीक एक प्रयोग किया गया ब्लॉक हटा दिया जाता है तो नए मुक्त ब्लॉक को नि: शुल्क मुक्त ब्लॉक के साथ विलय किया जा सकता है ताकि बड़े मुक्त ब्लॉक को प्रभावी ढंग से ढेर के विखंडन को कम किया जा सके।

The heap

ढेर

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

The stack

एक स्टैक के बजाय ढेर पर एक समारोह आवंटित किया जा सकता है?

नहीं, कार्यों के लिए सक्रियण रिकॉर्ड (यानी स्थानीय या स्वचालित चर) को स्टैक पर आवंटित किया जाता है जिसका उपयोग न केवल इन चरों को स्टोर करने के लिए किया जाता है, बल्कि नेस्टेड फ़ंक्शन कॉल का ट्रैक रखने के लिए भी किया जाता है।

ढेर कैसे प्रबंधित किया जाता है वास्तव में रनटाइम पर्यावरण पर है। सी उपयोग करता है malloc और सी ++ उपयोग करता है new, लेकिन कई अन्य भाषाओं में कचरा संग्रह है।

हालांकि, स्टैक प्रोसेसर आर्किटेक्चर से बारीकी से बंधे एक और निम्न स्तर की सुविधा है। पर्याप्त जगह नहीं होने पर ढेर बढ़ाना बहुत मुश्किल नहीं है क्योंकि इसे लाइब्रेरी कॉल में लागू किया जा सकता है जो ढेर को संभालता है। हालांकि, ढेर बढ़ाना अक्सर असंभव होता है क्योंकि स्टैक ओवरफ़्लो केवल तब बहुत ही देर हो जाता है जब यह बहुत देर हो जाती है; और निष्पादन के धागे को बंद करना एकमात्र व्यवहार्य विकल्प है।


664
2017-07-31 15:54



@ मार्टिन - अधिक अमूर्त स्वीकृत उत्तर की तुलना में एक बहुत अच्छा जवाब / स्पष्टीकरण। एक नमूना असेंबली प्रोग्राम जो स्टैक पॉइंटर्स / रजिस्टरों को दिखाता है, एक वी फंक्शन कॉल के साथ इस्तेमाल किया जा रहा है और अधिक चित्रकारी होगा। - Bikal Lem
प्रत्येक संदर्भ प्रकार मूल्य प्रकारों (int, स्ट्रिंग इत्यादि) की संरचना है। जैसा कि कहा जाता है, कि मूल्य प्रकारों को स्टैक में संग्रहीत किया जाता है, जब वे संदर्भ प्रकार का हिस्सा होते हैं तो यह कैसे काम करता है। - Nps
यह जवाब मेरी राय में सबसे अच्छा था, क्योंकि इससे मुझे यह समझने में मदद मिली कि वास्तव में एक रिटर्न स्टेटमेंट क्या है और यह इस "रिटर्न एड्रेस" से कैसे संबंधित है जो मैं हर समय आता हूं और फिर, फ़ंक्शन पर फ़ंक्शन को धक्का देने का क्या अर्थ है, और क्यों कार्यों को ढेर पर धकेल दिया जाता है। बहुत बढ़िया जवाब! - Alex
यह मेरी राय में सबसे अच्छा है, अर्थात् यह उल्लेख करने के लिए कि ढेर / ढेर हैं बहुत कार्यान्वयन विशिष्ट। अन्य जवाब एक मानते हैं बहुत भाषा और पर्यावरण / ओएस के बारे में चीजों के बारे में। +1 - Qix
आपका क्या मतलब है "फ़ंक्शन में कोड इन मानों का पता लगाने के लिए वर्तमान स्टैक पॉइंटर से ढेर को नेविगेट करने में सक्षम है।" ? क्या आप इस पर विस्तार कर सकते हैं? - Koray Tugay


निम्नलिखित सी # कोड में

public void Method1()
{
    int i = 4;
    int y = 2;
    class1 cls1 = new class1();
}

यहां बताया गया है कि स्मृति कैसे प्रबंधित की जाती है

Picture of variables on the stack

Local Variables जब तक फ़ंक्शन आमंत्रण स्टैक में जाता है तब तक केवल तब तक चलने की आवश्यकता होती है। ढेर का उपयोग चर के लिए किया जाता है जिसका जीवनकाल हम वास्तव में सामने नहीं जानते हैं, लेकिन हम उम्मीद करते हैं कि वे थोड़ी देर तक रहें। ज्यादातर भाषाओं में यह महत्वपूर्ण है कि हम संकलित समय पर जानते हैं कि एक चर कितना बड़ा है अगर हम इसे ढेर पर स्टोर करना चाहते हैं।

ऑब्जेक्ट्स (जो आकार में भिन्न होते हैं, हम उन्हें अपडेट करते हैं) ढेर पर जाते हैं क्योंकि हम सृजन के समय में नहीं जानते कि वे कितने समय तक चल रहे हैं। कई भाषाओं में ढेर वस्तुओं को खोजने के लिए कचरा इकट्ठा किया जाता है (जैसे कि cls1 ऑब्जेक्ट) जिसमें अब कोई संदर्भ नहीं है।

जावा में, अधिकांश ऑब्जेक्ट सीधे ढेर में जाते हैं। जब आप पॉइंटर्स से बात नहीं कर रहे हैं तो सी / सी ++ जैसी भाषाओं में, structs और कक्षाएं अक्सर ढेर पर रह सकती हैं।

अधिक जानकारी यहां पाई जा सकती है:

ढेर और ढेर स्मृति आवंटन के बीच अंतर «timmurphy.org

और यहाँ:

ढेर और ढेर पर वस्तुओं का निर्माण

यह आलेख ऊपर चित्र का स्रोत है: छह महत्वपूर्ण .NET अवधारणाएं: ढेर, ढेर, मूल्य प्रकार, संदर्भ प्रकार, मुक्केबाजी, और अनबॉक्सिंग - CodeProject

लेकिन ध्यान रखें कि इसमें कुछ त्रुटियां हो सकती हैं।


352
2017-11-09 12:28



यह गलत है। मैं और सीएल "स्थैतिक" चर नहीं हैं। उन्हें "स्थानीय" या "स्वचालित" चर कहा जाता है। यह एक बहुत ही महत्वपूर्ण भेद है। देखें [लिंक] stackoverflow.com/a/13326916/1763801 स्पष्टीकरण के लिए - davec
मैंने नहीं कहा कि वे स्थिर थे चर। मैंने कहा कि int और cls1 स्थिर हैं आइटम। उनकी याददाश्त स्थाई रूप से आवंटित की जाती है और इसलिए वे ढेर पर जाते हैं। यह किसी ऑब्जेक्ट के विपरीत है जिसके लिए गतिशील स्मृति आवंटन की आवश्यकता होती है जो इसलिए ढेर पर जाती है। - Snowcrash
मैं उद्धृत करता हूं "स्टेटिक आइटम ... स्टैक पर जाएं"। यह सिर्फ गलत है। स्टेटिक आइटम डेटा सेगमेंट में जाते हैं, स्वचालित आइटम स्टैक पर जाते हैं। - davec
जो भी कोडप्रोजेक्ट आलेख लिखा है उसे पता नहीं है कि वह किस बारे में बात कर रहा है। उदाहरण के लिए, वह कहता है "आदिम लोगों को स्थिर प्रकार की स्मृति की आवश्यकता होती है" जो पूरी तरह से असत्य है। गतिशील रूप से ढेर में प्राइमेटिव आवंटित करने से आपको कुछ भी नहीं रोकता है, बस "int array [] = new int [num]" और voila, .NET में गतिशील रूप से आवंटित प्राइमेटिव्स जैसे कुछ लिखें। यह सिर्फ कई त्रुटियों में से एक है। - davec
मैंने आपकी पोस्ट संपादित की क्योंकि आपने स्टैक और ढेर में क्या चल रहा है, इस बारे में गंभीर तकनीकी गलतियां की हैं। - Tom Leys


ढेर जब आप किसी फ़ंक्शन को कॉल करते है