memory management - ढेर और ढेर क्या और कहाँ हैं?




memory-management language-agnostic (17)

क्रमबद्ध करें

एक स्टैक का उपयोग स्थिर स्मृति आवंटन और गतिशील स्मृति आवंटन के लिए एक ढेर, दोनों कंप्यूटर की रैम में संग्रहीत किया जाता है।

विस्तार से

ढेर

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

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

यहां और अधिक पाया जा सकता here

ढेर

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

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

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

ढेर के विपरीत, ढेर पर बनाए गए चर किसी भी फ़ंक्शन द्वारा आपके प्रोग्राम में कहीं भी पहुंच योग्य होते हैं। ढेर चर अनिवार्य रूप से वैश्विक स्तर पर वैश्विक हैं।

यहां और अधिक पाया जा सकता here

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

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

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

एक बहु थ्रेडेड स्थिति में प्रत्येक धागे का अपना पूरी तरह से स्वतंत्र ढेर होगा, लेकिन वे ढेर साझा करेंगे। ढेर धागा विशिष्ट है और ढेर आवेदन विशिष्ट है। अपवाद हैंडलिंग और थ्रेड निष्पादन में विचार करना स्टैक महत्वपूर्ण है।

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

रन-टाइम पर, यदि एप्लिकेशन को अधिक ढेर की आवश्यकता होती है, तो यह स्मृति को मुफ्त मेमोरी से आवंटित कर सकती है और यदि स्टैक को स्मृति की आवश्यकता होती है, तो यह एप्लिकेशन के लिए फ्री मेमोरी आवंटित स्मृति से स्मृति आवंटित कर सकता है।

यहां तक कि, और अधिक विस्तार दिया जाता है here और here

अब अपने प्रश्न के उत्तरों पर आओ ।

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

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

यहां और अधिक पाया जा सकता here

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

पहले से ही दिया गया है।

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

यहां अधिक पाया जा सकता here

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

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

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

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

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

विवरण here से पाया जा सकता here

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

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

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

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

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

ढेर

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

ढेर

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

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

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

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

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


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

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

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

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

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

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

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

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

और यहाँ:

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


वर्चुअल मेमोरी में प्रत्येक प्रक्रिया का ढेर , ढेर और डेटा :


एक ढेर क्या है?

एक ढेर वस्तुओं का एक ढेर है, आमतौर पर एक जिसे व्यवस्थित ढंग से व्यवस्थित किया जाता है।

कंप्यूटिंग आर्किटेक्चर में ढेर स्मृति के क्षेत्र हैं जहां डेटा को अंतिम-इन-फर्स्ट-आउट तरीके से जोड़ा या हटा दिया जाता है।
एक बहु थ्रेडेड अनुप्रयोग में, प्रत्येक थ्रेड का अपना ढेर होगा।

ढेर क्या है?

एक ढेर चीजों का एक बेकार संग्रह है जो खतरनाक रूप से ढेर हो जाता है।

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

दोनों साथ में

एक बहु थ्रेडेड अनुप्रयोग में, प्रत्येक थ्रेड का अपना ढेर होगा। लेकिन, सभी अलग-अलग धागे ढेर को साझा करेंगे।
चूंकि विभिन्न धागे एक बहु-थ्रेडेड अनुप्रयोग में ढेर को साझा करते हैं, इसका मतलब यह भी है कि धागे के बीच कुछ समन्वय होना चाहिए ताकि वे ढेर में स्मृति के उसी टुकड़े तक पहुंचने और उसका उपयोग करने की कोशिश न करें। उसी समय।

जो तेज है - ढेर या ढेर? और क्यों?

ढेर ढेर से बहुत तेज है।
यह इस तरह है कि ढेर पर स्मृति आवंटित की जाती है।
ढेर पर स्मृति आवंटित करना उतना आसान है जितना स्टैक पॉइंटर को ऊपर ले जाना।

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

जावा मेमोरी मॉडल

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


ढेर:

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

ढेर:

  • स्टैक की तरह कंप्यूटर रैम में संग्रहीत।
  • सी ++ में, ढेर पर चर को मैन्युअल रूप से नष्ट किया जाना चाहिए और कभी भी दायरे से बाहर नहीं होना चाहिए। डेटा 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;

ढेर

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

ढेर

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

कुछ सेंट: मुझे लगता है, स्मृति ग्राफिकल और अधिक सरल बनाने के लिए अच्छा होगा:


तीर - दिखाएं जहां ढेर और ढेर बढ़ते हैं, प्रक्रिया स्टैक आकार की सीमा है, ओएस में परिभाषित, थ्रेड स्टैक आकार सीमा थ्रेड में पैरामीटर द्वारा आमतौर पर बनाते हैं। उदाहरण के लिए 32 बिट 2-4 जीबी के लिए आमतौर पर प्रक्रिया अधिकतम वर्चुअल मेमोरी आकार से सीमित हैप।

इतना आसान तरीका: प्रक्रिया ढेर सामान्य मामले में स्मृति आवंटन के लिए malloc () जैसे स्मृति प्रक्रिया के लिए प्रक्रिया और सभी धागे के अंदर सामान्य है ।

स्टैक सामान्य केस फ़ंक्शन रिटर्न पॉइंटर्स और चर में स्टोर के लिए त्वरित मेमोरी है, फ़ंक्शन कॉल में पैरामीटर के रूप में संसाधित, स्थानीय फ़ंक्शन वेरिएबल्स।


चूंकि कुछ जवाब नाइटपिक हो गए, मैं अपनी पतंग का योगदान करने जा रहा हूं।

हैरानी की बात है कि, किसी ने भी उल्लेख नहीं किया है कि एकाधिक (यानी चल रहे ओएस-स्तरीय धागे की संख्या से संबंधित नहीं) कॉल स्टैक न केवल विदेशी भाषाओं (पोस्टस्क्रिप्ट) या प्लेटफार्मों (इंटेल इटेनियम) में पाए जाते हैं, बल्कि fibers , हरे धागे में भी पाए जाते हैं और coroutines कुछ कार्यान्वयन ।

फाइबर, हरे धागे और कोरआउट कई तरह के होते हैं, जो बहुत भ्रम पैदा करते हैं। फाइबर और हरे धागे के बीच का अंतर यह है कि पूर्व उपयोग सहकारी मल्टीटास्किंग, जबकि बाद में सहकारी या प्रीपेप्टिव एक (या यहां तक ​​कि दोनों) भी हो सकता है। फाइबर और कोरआउट के बीच भेद के लिए, here देखें ।

किसी भी मामले में, फाइबर, हरे धागे और कोरआउट दोनों के उद्देश्य एक साथ कई निष्पादन निष्पादित होते हैं, लेकिन एक समान ओएस-स्तरीय थ्रेड के भीतर समानांतर में नहीं ( भेद के लिए यह SO प्रश्न देखें ), एक दूसरे से नियंत्रण को आगे और आगे स्थानांतरित करना एक संगठित फैशन में।

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

ध्यान दें कि मैंने कहा " आमतौर पर प्रति समारोह एक अलग ढेर है"। दोनों कर रहे हैं stackful और stackless couroutines के कार्यान्वयन। सबसे उल्लेखनीय stackful सी ++ कार्यान्वयन हैं Boost.Coroutine और माइक्रोसॉफ्ट पीपीएल की async/await। (हालांकि, सी ++ के पुन: शुरू करने योग्य कार्य (उर्फ " asyncऔर await"), जिन्हें सी ++ 17 के लिए प्रस्तावित किया गया था, वे स्टैकलेस कोरआउट का उपयोग करने की संभावना रखते हैं।)

सी ++ मानक पुस्तकालय के लिए फाइबर प्रस्ताव आगामी है। इसके अलावा, कुछ तीसरे पक्ष के libraries । पाइथन और रूबी जैसी भाषाओं में ग्रीन थ्रेड बेहद लोकप्रिय हैं।


मुझे लगता है कि कई अन्य लोगों ने आपको इस मामले पर अधिकतर सही उत्तर दिए हैं।

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


मेरे पास आपके साथ साझा करने के लिए कुछ है, हालांकि प्रमुख बिंदु पहले से ही लिखे गए हैं।

ढेर

  • बहुत तेज पहुंच
  • राम में संग्रहीत
  • फ़ंक्शन कॉल स्थानीय चर और फ़ंक्शन पैरामीटर के साथ यहां लोड किए जाते हैं।
  • जब कार्यक्रम एक दायरे से बाहर हो जाता है तो अंतरिक्ष स्वचालित रूप से मुक्त हो जाता है।
  • अनुक्रमिक स्मृति में संग्रहीत।

ढेर

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

दिलचस्प नोट:

  • अगर फ़ंक्शन कॉल ढेर में संग्रहीत किया गया था, तो इसके परिणामस्वरूप 2 गन्दा अंक होंगे:
    1. ढेर में अनुक्रमिक भंडारण के कारण, निष्पादन तेज है। ढेर में भंडारण के परिणामस्वरूप भारी समय की खपत होती है जिसके परिणामस्वरूप पूरे कार्यक्रम को धीरे-धीरे निष्पादित किया जाता है।
    2. यदि कार्य ढेर में संग्रहीत किए गए थे (सूचक द्वारा इंगित गन्दा भंडारण), तो कॉलर पता वापस लौटने का कोई तरीका नहीं होगा (जो ढेर स्मृति में क्रमिक भंडारण के कारण देता है)।

फीडबैक अच्छी तरह से हैं।


1 9 80 के दशक में, यूनिक्स ने बड़ी कंपनियों के साथ बनीज की तरह प्रचार किया। एक्सक्सन ने इतिहास में खोए गए दर्जनों ब्रांड नामों के रूप में एक किया था। कई कार्यान्वयनकर्ताओं के विवेकानुसार स्मृति कैसे निर्धारित की गई थी।

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

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

एक ठेठ मेमोरी ब्लॉक बीएसएस (शून्य मानों का एक ब्लॉक) था जिसे गलती से एक निर्माता की पेशकश में शून्य नहीं किया गया था। एक और डेटा था जिसमें तारों और संख्याओं सहित प्रारंभिक मान शामिल थे। एक तिहाई सीओडीई जिसमें सीआरटी (सी रनटाइम), मुख्य, कार्य, और पुस्तकालय शामिल थे।

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


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

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


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

ढेर मेमोरी गतिशील स्मृति आवंटन का क्षेत्र है (स्पष्ट "नया" या "आवंटित" कॉल)। यह एक विशेष डेटा संरचना है जो विभिन्न आकारों और उनकी आवंटन स्थिति की स्मृति के ब्लॉक का ट्रैक रख सकती है।

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


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

ढेर पर आप वापसी पते को सहेजते हैं और कॉल → पुश / रेट → पॉप सीधे हार्डवेयर में प्रबंधित किया जाता है।

आप मानकों को पारित करने के लिए ढेर का उपयोग कर सकते हैं .. भले ही यह रजिस्टरों का उपयोग करने से धीमा हो (चाहे एक माइक्रोप्रोसेसर गुरु या 1 9 80 के दशक की बीआईओएस पुस्तक ...)

  • ढेर के बिना कोई माइक्रोप्रोसेसर काम कर सकता है। (हम एक कार्यक्रम की कल्पना नहीं कर सकते हैं, यहां तक ​​कि असेंबली / कार्यों के बिना असेंबली भाषा में भी)
  • ढेर के बिना यह कर सकते हैं। (एक असेंबली भाषा कार्यक्रम बिना काम कर सकता है, क्योंकि ढेर एक ओएस अवधारणा है, मॉलोक के रूप में, यह ओएस / लीब कॉल है।

ढेर उपयोग तेज है:

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

  • परिचय

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

चित्रा 4-1 वर्चुअल मेमोरी अवधारणा का उपयोग करते हुए, ओएस द्वारा भौतिक स्मृति को सारणीबद्ध और प्रबंधित किया गया है। वर्चुअल मेमोरी ओएस द्वारा प्रबंधित भौतिक स्मृति का सार दृश्य है। वर्चुअल मेमोरी केवल आभासी पतों की एक श्रृंखला है, और आवश्यकता होने पर इन वर्चुअल पतों को सीपीयू द्वारा भौतिक पते में अनुवादित किया जाता है।

चित्रा 4-1। सीएलआर स्मृति अमूर्तता

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

  • सीएलआर और ओएस के बीच मेमोरी इंटरैक्शन

निम्नलिखित सी # अनुप्रयोग को डीबग करते समय स्टैक ट्रेस को देखकर, WinDbg का उपयोग करके, आप देखेंगे कि सीएलआर अंतर्निहित ओएस मेमोरी प्रबंधन सेवाओं का उपयोग कैसे करता है (उदाहरण के लिए, KERNEL32.dll से HeapFree विधि, ntdll.dll से RtlpFreeHeap विधि) को लागू करने के लिए इसका अपना मेमोरी मॉडल:

using System;
namespace CH_04
{
    class Program
    {
        static void Main(string[] args)
        {
            Book book = new Book();
            Console.ReadLine();
        }
    }

    public class Book
    {
        public void Print() { Console.WriteLine(ToString()); }
    }
}

कार्यक्रम की संकलित असेंबली डीबगिंग शुरू करने के लिए WinDbg में लोड की गई है। डीबगिंग सत्र आरंभ करने के लिए आप निम्न आदेशों का उपयोग करते हैं:

0: 000> एससीई एलडी clrjit

0: 000> जी

0: 000> .loadby sos clr

0: 000> .load सी: \ विंडोज \ माइक्रोसॉफ्ट.NET \ Framework \ v4.0.30319 \ sos.dll

फिर, आप! Bpmd कमांड का उपयोग कर प्रोग्राम क्लास की मुख्य विधि पर ब्रेकपॉइंट सेट करते हैं:

0: 000>! Bpmd CH_04.exe CH_04.Program.Main

ब्रेकपॉइंट पर निष्पादन जारी रखने और ब्रेक करने के लिए, जी कमांड निष्पादित करें:

0: 000> जी

जब निष्पादन ब्रेकपॉइंट पर टूट जाता है, तो आप वर्तमान प्रक्रिया के लिए चल रहे सभी थ्रेडों के स्टैक ट्रेस विवरण देखने के लिए! Eestack कमांड का उपयोग करते हैं। निम्न आउटपुट अनुप्रयोग के लिए चल रहे सभी थ्रेड के लिए स्टैक ट्रेस दिखाता है CH_04.exe:

0: 000>! ईस्टैक

थ्रेड 0

वर्तमान फ्रेम: (MethodDesc 00233800 +0 CH_04.Program.Main (System.String []))

चाइल्डईबीपी रेटएडर कॉलर, कैली

0022ed24 5faf21db clr! CallDescrWorker + 0x33

/ ट्रेस हटा दिया /

0022f218 77712d68 ntdll! RtlFreeHeap + 0x142, ntdll को कॉल करना! RtlpFreeHeap

0022f238 771df1ac KERNEL32! हेपफ़्री + 0x14, कॉलिंग ntdll! RtlFreeHeap

0022f24c 5fb4c036 clr! EEHeapFree + 0x36, KERNEL32 को कॉल करना! HeapFree

0022f260 5fb4c09d clr! EEHeapFreeInProcessHeap + 0x24, कॉलर क्लियर! EEHeapFree

0022f274 5fb4c06d clr! ऑपरेटर हटाएं [] + 0x30, क्लियर कॉलिंग! EEHeapFreeInProcessHeap / ट्रेस हटा दिया /

0022f4d0 7771316f ntdll! RtlpFreeHeap + 0xb7a, ntdll को कॉल करना! _SEH_epilog4

0022f4d4 77712d68 ntdll! RtlFreeHeap + 0x142, ntdll को कॉल करना! RtlpFreeHeap

0022f4f4 771df1ac KERNEL32! हेपफ़्री + 0x14, कॉलिंग ntdll! RtlFreeHeap

/ ट्रेस हटा दिया /

यह स्टैक ट्रेस इंगित करता है कि सीएलआर अपने मेमोरी मॉडल को लागू करने के लिए ओएस मेमोरी प्रबंधन सेवाओं का उपयोग करता है। .NET में कोई भी मेमोरी ऑपरेशन सीएलआर मेमोरी लेयर के माध्यम से ओएस मेमोरी प्रबंधन परत में जाता है।

चित्रा 4-2 रनटाइम पर सीएलआर द्वारा उपयोग किए जाने वाले एक सामान्य सी # एप्लिकेशन मेमोरी मॉडल को दिखाता है।

चित्रा 4-2 । एक ठेठ सी # अनुप्रयोग मेमोरी मॉडल

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

अधिक जानकारी के लिए, इस पुस्तक का संदर्भ लें:

सी # Deconstructed: पता लगाएँ कि सी # .NET फ्रेमवर्क पर कैसे काम करता है

यह पुस्तक + ClrViaC # + विंडोज आंतरिक ओएस के साथ गहराई और संबंध में नेट फ्रेमवर्क ज्ञात उत्कृष्ट संसाधन हैं।





heap