2011-11-17 28 views
25

संभव डुप्लिकेट:
What and where are the stack and heapमेमोरी स्टैक और ढेर में क्यों विभाजित है?

मैं ढेर ढेर बनाम पर सवाल की एक जोड़ी है।

मूल बात यह जानना है कि ढेर ढेर से तेज है, लेकिन सीमित है। (यदि मैं गलत हूं तो मुझे सही करों)।

हालांकि, मैंने हमेशा सोचा कि कैसे ढेर और ढेर ठीक काम करते हैं। राम स्मृति का सिर्फ एक हिस्सा है, इसे 'ढेर' और 'ढेर' में विभाजित नहीं किया गया है (या यह है?)। यदि ऐसा है, तो हम स्मृति को पहले स्थान पर ढेर और ढेर में क्यों विभाजित करते हैं?

ओएस हमें केवल स्टैक पर सबकुछ आवंटित करने में सक्षम होने की अनुमति दे सकता है -> सब कुछ तेजी से चला जाता है -> खुश दुनिया?

मुझे पूरा यकीन है कि यह मामला नहीं है। लेकिन क्यों!? क्या कोई मुझे गहराई से जवाब दे सकता है?

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

+3

http://stackoverflow.com/questions/7123936/why-is-there-a-stack-and-a-heap – drdwilcox

+2

http://stackoverflow.com/questions/79923/what-and-where-are -the-stack-and-heap –

उत्तर

6

आप केवल एक ढेर का उपयोग नहीं कर सकते क्योंकि एक ढेर एक आखिरी में फर्स्ट-आउट आवंटन & आवंटन रद्द करने के क्रम की आवश्यकता है (यानी आप केवल नवीनतम आवंटित डेटा पुनःआवंटन कर सकते हैं; एक ढेर में आप कुछ पुराने डेटा पुनःआवंटन और न कुछ रख सकते हैं नया एक)।

दरअसल, आप ढेर से छुटकारा पा सकते हैं (केवल ढेर को रखते हुए)। एपेल का पेपर Garbage Collection Can Be Faster Than Stack Allocation और उसकी Compiling with Continuation पुस्तक देखें।

और ढेर में एक अच्छी परिभाषित अर्थ नहीं है ("गतिशील रूप से आवंटित स्मृति जो स्टैक पर नहीं है" के अलावा)। असल में, लिनक्स सिस्टम पर, mmap सिस्टम कॉल का उपयोग करके स्मृति का एक बड़ा हिस्सा आवंटित करना काफी तेज़ है (लेकिन malloc कार्यान्वयन mmap से बचने का प्रयास करें और free -d स्मृति का पुन: उपयोग करना पसंद करें)। मुद्दा छोटी स्मृति क्षेत्र का आवंटन है।

और garbage collection techniques के बारे में और पढ़ें। सी या सी ++ में आप Boehm's GC

का उपयोग कर सकते हैं एक स्टैक अक्सर उपयोगी होता है, विशेष रूप से रिकर्सिव फ़ंक्शन कॉल के लिए। यह बहुत उपयोगी है (उदाहरण के लिए सी में) कि आज के प्रोसेसर में आमतौर पर एक समर्पित स्टैक पॉइंटर रजिस्टर होता है (& आरईटी मशीन निर्देशों द्वारा & लौटने के लिए कॉल किया जाता है)। लेकिन यह हमेशा मामला नहीं था; कुछ प्रोसेसर (जैसे आईबीएम 360) पर, स्टैक पॉइंटर एक पारंपरिक रजिस्टर है, हार्डकोडेड नहीं।

+0

बहुत उपयोगी जानकारी, धन्यवाद :) – xcrypt

0

स्मृति दोनों ही के लिए समान है, लेकिन ढेर और ढेर 2 अलग-अलग डेटा संरचनाएं हैं जो विभिन्न उद्देश्यों के लिए उपयोगी हैं।

स्टैक एक बहुत ही प्राचीन अमूर्त है जिसे किसी भी माइक्रो प्रोसेसर द्वारा आवश्यक है ताकि कुछ ऑपरेंड (आमतौर पर प्रोसेसर रजिस्ट्रार या मेमोरी एड्रेस) पर निर्देश निष्पादित किया जा सके।

ढेर एक सामान्य आवंटन स्मृति क्षेत्र है जहां आम तौर पर आप उस डेटा को स्टोर करना चाहते हैं जो ढेर से बंधे नहीं है, यह उनका जीवनकाल लंबा है कि अगर ढेर में संग्रहीत किया जाता है, या एक और तरीका कहा जाता है, तो डेटा जा रहा है कोड के विभिन्न हिस्सों तक पहुंच प्राप्त करें।

+0

ठीक है, मैं मुख्य कार्य में स्टैक पर कुछ ऑब्जेक्ट आवंटित कर सकता हूं, और पूरे कार्यक्रम में इसका उपयोग कर सकता हूं, मुझे इसके लिए ढेर की आवश्यकता नहीं है। आपका तर्क यह हो सकता है कि ढेर सीमित है, लेकिन मेरे सवालों के बारे में पूछने के लिए एक चीज थी: स्टैक सीमित क्यों है? (ऊपर वर्णित कारणों के लिए) – xcrypt

+0

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

23

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

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

हीप: ढेर अलग है - इसमें कोई विशेष आदेश नहीं है। यदि आप कोड के ब्लॉक में स्मृति आवंटित करना चाहते हैं और उस मेमोरी को ब्लॉक के अंत से चारों ओर चिपकाना है, तो आप इसे ढेर पर आवंटित करते हैं। बेशक, आपको कहीं भी पॉइंटर/संदर्भ स्टोर करने की आवश्यकता होगी ताकि अन्य कोड उस स्मृति को पा सके; अधिकांश भाषाएं आवास प्रदान करती हैं।

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

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

उदाहरण: कल्पना कीजिए कि आप एक वर्ड प्रोसेसर बना रहे हैं। आप समय से पहले नहीं जान सकते कि दस्तावेज़ कितना बड़ा होगा, या यहां तक ​​कि एक ही समय में कितने दस्तावेज़ उपयोग किए जाएंगे। साथ ही, आप चाहते हैं कि उपयोगकर्ता के दस्तावेज़ स्मृति में बने रहें जब तक कि उपयोगकर्ता उन्हें खोलना न चाहें। यदि आप स्टैक पर दस्तावेज़ों के लिए स्मृति आवंटित करने का प्रयास करते हैं तो आपको एक से अधिक बार एक से अधिक खुला होना मुश्किल लगेगा, और आपको एक ऐसा फ़ंक्शन बनाना होगा जो दस्तावेज़ बनाता है, संपादित करता है, सहेजता है और बंद करता है। ढेर पर जगह आवंटित करने से आप जितने चाहें उतने दस्तावेज तैयार कर सकते हैं, प्रत्येक डेटा में जो डेटा शामिल है, उसके लिए उपयुक्त है, और दस्तावेजों के जीवनकाल को किसी भी विशेष कार्य के जीवनकाल में टालने से बचने के लिए।

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

+0

क्या आप मुझे कुछ बिंदु का उदाहरण दे सकते हैं जहां मुझे ढेर का उपयोग करने के लिए मजबूर किया गया है? उदाहरण के लिए, मैं केवल स्टैण्ड पर सबकुछ आवंटित कर सकता हूं जो मुझे पूरे कार्यक्रम के लिए मूल कार्य में आवश्यक है, और बच्चे के कार्यों में पते से सबकुछ पास कर सकता है। संपादित करें: आइए अनदेखा करें कि प्रश्न के लिए रैम मेमोरी भरने से स्टैक किसी और चीज से सीमित है। – xcrypt

+0

@xcrypt यह आवश्यक होगा कि आप अपने प्रोग्राम द्वारा किए जा सकने वाले हर मेमोरी आवंटन के बारे में पहले से ही जान सकें। वैकल्पिक रूप से, आप अपने ढेर पर एक विशाल ब्लॉक आवंटित कर सकते हैं जिससे आप गतिशील रूप से स्मृति आवंटित कर सकते हैं। वह ब्लॉक एक ढेर के कार्यात्मक समकक्ष होगा। मैं उपरोक्त एक उदाहरण जोड़ूंगा। – Caleb

+0

आपने उल्लेख किया है कि कंपाइलर रनटाइम से पहले आवश्यक स्टैक स्पेस की मात्रा को आंकड़े बताता है, है ना? क्या यह भी रिकर्सन के मामले के लिए सच है? क्योंकि अगर यह सही है तो संकलक कोड को संकलित करने के बाद सही अनंत पुनरावृत्ति को संकेत देने में सक्षम नहीं होना चाहिए? – Dubby

संबंधित मुद्दे