यह वास्तव में सिस्टम पर निर्भर करता है, लेकिन वर्चुअल मेमोरी वाले आधुनिक ओएस अपनी प्रक्रिया छवियों को लोड करते हैं और मेमोरी को कुछ इस तरह आवंटित करते हैं:
+---------+
| stack | function-local variables, return addresses, return values, etc.
| | often grows downward, commonly accessed via "push" and "pop" (but can be
| | accessed randomly, as well; disassemble a program to see)
+---------+
| shared | mapped shared libraries (C libraries, math libs, etc.)
| libs |
+---------+
| hole | unused memory allocated between the heap and stack "chunks", spans the
| | difference between your max and min memory, minus the other totals
+---------+
| heap | dynamic, random-access storage, allocated with 'malloc' and the like.
+---------+
| bss | Uninitialized global variables; must be in read-write memory area
+---------+
| data | data segment, for globals and static variables that are initialized
| | (can further be split up into read-only and read-write areas, with
| | read-only areas being stored elsewhere in ROM on some systems)
+---------+
| text | program code, this is the actual executable code that is running.
+---------+
यह कई सामान्य वर्चुअल-मेमोरी सिस्टम पर सामान्य प्रक्रिया पता स्थान है। "छेद" आपकी कुल मेमोरी का आकार है, जो अन्य सभी क्षेत्रों द्वारा उठाए गए स्थान को घटाता है; यह ढेर को बढ़ने के लिए बड़ी मात्रा में जगह देता है। यह "वर्चुअल" भी है, जिसका अर्थ है कि यह अनुवाद तालिका के माध्यम से आपकी वास्तविक मेमोरी में मैप करता है , और वास्तव में वास्तविक मेमोरी में किसी भी स्थान पर संग्रहीत किया जा सकता है। यह एक प्रक्रिया को किसी अन्य प्रक्रिया की मेमोरी तक पहुंचने से बचाने के लिए किया जाता है, और प्रत्येक प्रक्रिया को लगता है कि यह एक संपूर्ण सिस्टम पर चल रहा है।
ध्यान दें कि, की स्थिति, जैसे, ढेर और ढेर कुछ प्रणालियों पर एक अलग क्रम में हो सकते हैं ( बिली ओ'नील का जवाब देखें) Win32 पर अधिक जानकारी के लिए नीचे देखें)।
अन्य प्रणालियाँ बहुत भिन्न हो सकती हैं । उदाहरण के लिए, DOS वास्तविक मोड में चलता है , और प्रोग्राम चलाने के दौरान इसका मेमोरी आवंटन बहुत अलग दिखता है:
+-----------+ top of memory
| extended | above the high memory area, and up to your total memory; needed drivers to
| | be able to access it.
+-----------+ 0x110000
| high | just over 1MB->1MB+64KB, used by 286s and above.
+-----------+ 0x100000
| upper | upper memory area, from 640kb->1MB, had mapped memory for video devices, the
| | DOS "transient" area, etc. some was often free, and could be used for drivers
+-----------+ 0xA0000
| USER PROC | user process address space, from the end of DOS up to 640KB
+-----------+
|command.com| DOS command interpreter
+-----------+
| DOS | DOS permanent area, kept as small as possible, provided routines for display,
| kernel | *basic* hardware access, etc.
+-----------+ 0x600
| BIOS data | BIOS data area, contained simple hardware descriptions, etc.
+-----------+ 0x400
| interrupt | the interrupt vector table, starting from 0 and going to 1k, contained
| vector | the addresses of routines called when interrupts occurred. e.g.
| table | interrupt 0x21 checked the address at 0x21*4 and far-jumped to that
| | location to service the interrupt.
+-----------+ 0x0
आप देख सकते हैं कि डॉस ने बिना किसी सुरक्षा के साथ ऑपरेटिंग सिस्टम मेमोरी तक सीधे पहुंच की अनुमति दी, जिसका अर्थ था कि उपयोगकर्ता-अंतरिक्ष कार्यक्रम आम तौर पर सीधे पहुंच सकते हैं या किसी भी चीज़ को अधिलेखित कर सकते हैं जो उन्हें पसंद है।
प्रोसेस एड्रेस स्पेस में, हालांकि, प्रोग्राम समान दिखने के लिए थे, केवल उन्हें कोड सेगमेंट, डेटा सेगमेंट, हीप, स्टैक सेगमेंट, आदि के रूप में वर्णित किया गया था, और इसे थोड़ा अलग तरीके से मैप किया गया था। लेकिन अधिकांश सामान्य क्षेत्र अभी भी थे।
प्रोग्राम को लोड करने और मेमोरी में आवश्यक साझा करने पर, और प्रोग्राम के हिस्सों को सही क्षेत्रों में वितरित करने पर, ओएस आपकी प्रक्रिया को क्रियान्वित करना शुरू कर देता है जहां भी इसकी मुख्य विधि होती है, और आपका प्रोग्राम वहां से शुरू होता है, जब आवश्यक हो तो सिस्टम कॉल करना यह उनकी जरूरत है।
विभिन्न प्रणालियों (एम्बेडेड, जो भी हो) में बहुत अलग आर्किटेक्चर हो सकते हैं, जैसे स्टैकलेस सिस्टम, हार्वर्ड आर्किटेक्चर सिस्टम (कोड और डेटा को अलग-अलग भौतिक मेमोरी में रखा जा रहा है), सिस्टम जो वास्तव में बीएसएस को केवल-पढ़ने योग्य मेमोरी में रखते हैं (शुरू में सेट द्वारा प्रोग्रामर), आदि। लेकिन यह सामान्य है।
तुमने कहा था:
मुझे यह भी पता है कि एक कंप्यूटर प्रोग्राम दो प्रकार की मेमोरी का उपयोग करता है: स्टैक और हीप, जो कंप्यूटर की प्राथमिक मेमोरी का भी हिस्सा हैं।
"स्टैक" और "हीप" स्मृति के बजाय (आवश्यक) शारीरिक रूप से अलग "प्रकार" के बजाय केवल अमूर्त अवधारणाएं हैं।
एक ढेर केवल एक अंतिम-इन, पहली-आउट डेटा संरचना है। X86 आर्किटेक्चर में, इसे वास्तव में अंत से एक ऑफसेट का उपयोग करके यादृच्छिक रूप से संबोधित किया जा सकता है, लेकिन इसमें से आइटम जोड़ने और हटाने के लिए सबसे आम कार्य PUSH और POP हैं। यह आमतौर पर फ़ंक्शन-स्थानीय चर (तथाकथित "स्वचालित भंडारण"), फ़ंक्शन तर्क, रिटर्न पते आदि (अधिक नीचे) के लिए उपयोग किया जाता है
एक "हीप" स्मृति के एक टुकड़े के लिए एक उपनाम है जिसे मांग पर आवंटित किया जा सकता है, और यादृच्छिक रूप से संबोधित किया जाता है (मतलब, आप इसमें किसी भी स्थान तक सीधे पहुंच सकते हैं)। यह आमतौर पर डेटा संरचनाओं के लिए उपयोग किया जाता है जो आप रनटाइम पर आवंटित करते हैं (सी ++ में, उपयोग new
और delete
, औरmalloc
सी में दोस्तों, आदि)।
स्टैक और हीप, x86 आर्किटेक्चर पर, दोनों आपके सिस्टम मेमोरी (RAM) में भौतिक रूप से निवास करते हैं, और वर्चुअल मेमोरी आवंटन के माध्यम से ऊपर बताए गए प्रोसेस एड्रेस स्पेस में मैप किए जाते हैं।
रजिस्टरों (अभी भी 86 पर), शारीरिक रूप से प्रोसेसर (के रूप में राम के खिलाफ) के अंदर रहते हैं, और पाठ क्षेत्र से, प्रोसेसर के द्वारा लोड किए गए हैं (और यह भी स्मृति या अन्य स्थानों में कहीं और से लोड किया जा सकता सीपीयू निर्देश पर निर्भर करता है कि वास्तव में क्रियान्वित होते हैं)। वे अनिवार्य रूप से बहुत छोटे, बहुत तेज़ ऑन-चिप मेमोरी लोकेशन हैं जो कई अलग-अलग उद्देश्यों के लिए उपयोग किए जाते हैं।
रजिस्टर लेआउट आर्किटेक्चर पर अत्यधिक निर्भर है (वास्तव में, रजिस्टर, इंस्ट्रक्शन सेट, और मेमोरी लेआउट / डिज़ाइन, वास्तव में "आर्किटेक्चर" से क्या अभिप्राय है), और इसलिए मैं इस पर विस्तार नहीं करूंगा, लेकिन आपको लेने की सलाह देता हूं उन्हें बेहतर समझने के लिए असेंबली लैंग्वेज कोर्स।
आपका प्रश्न:
निर्देशों के निष्पादन के लिए किस बिंदु पर स्टैक का उपयोग किया जाता है? निर्देश रैम से, स्टैक तक, रजिस्टरों में जाते हैं?
स्टैक (सिस्टम / भाषाओं में जो उनके पास हैं और उनका उपयोग करते हैं) को अक्सर इस तरह से उपयोग किया जाता है:
int mul( int x, int y ) {
return x * y; // this stores the result of MULtiplying the two variables
// from the stack into the return value address previously
// allocated, then issues a RET, which resets the stack frame
// based on the arg list, and returns to the address set by
// the CALLer.
}
int main() {
int x = 2, y = 3; // these variables are stored on the stack
mul( x, y ); // this pushes y onto the stack, then x, then a return address,
// allocates space on the stack for a return value,
// then issues an assembly CALL instruction.
}
इस तरह एक सरल कार्यक्रम लिखें, और फिर इसे विधानसभा ( gcc -S foo.c
यदि आपके पास जीसीसी तक पहुंच है) के लिए संकलित करें, और एक नज़र डालें। असेंबली का पालन करना बहुत आसान है। आप देख सकते हैं कि स्टैक का उपयोग फंक्शन लोकल वेरिएबल के लिए किया जाता है, और कॉलिंग फंक्शन्स के लिए, उनके तर्कों और रिटर्न वैल्यूज़ को स्टोर करने के लिए। ऐसा इसलिए भी है क्योंकि जब आप कुछ ऐसा करते हैं:
f( g( h( i ) ) );
इन सभी को बदले में बुलाया जाता है। यह वस्तुतः फ़ंक्शन कॉल और उनके तर्कों का एक ढेर बना रहा है, उन्हें क्रियान्वित कर रहा है, और फिर उन्हें बंद कर देता है क्योंकि यह वापस नीचे (या ऊपर) हवाएं होती हैं। हालांकि, जैसा कि ऊपर उल्लेख किया गया है, स्टैक (x86 पर) वास्तव में आपकी प्रक्रिया मेमोरी स्पेस (आभासी मेमोरी में) में रहता है, और इसलिए इसे सीधे हेरफेर किया जा सकता है; यह निष्पादन के दौरान एक अलग कदम नहीं है (या कम से कम प्रक्रिया के लिए रूढ़िवादी है)।
FYI करें, उपरोक्त C कॉलिंग कन्वेंशन है , जिसका उपयोग C ++ द्वारा भी किया जाता है। अन्य भाषाएँ / सिस्टम एक अलग क्रम में स्टैक पर तर्कों को धक्का दे सकते हैं, और कुछ भाषाएँ / प्लेटफ़ॉर्म भी स्टैक का उपयोग नहीं करते हैं, और इसके बारे में विभिन्न तरीकों से चलते हैं।
यह भी ध्यान दें, ये C कोड निष्पादन की वास्तविक रेखाएँ नहीं हैं। संकलक ने उन्हें आपके निष्पादन योग्य में मशीन भाषा निर्देशों में परिवर्तित कर दिया है। तब उन्हें (आम तौर पर) TEXT क्षेत्र से CPU पाइपलाइन में कॉपी किया जाता है, फिर CPU रजिस्टरों में, और वहां से निष्पादित किया जाता है। [यह गलत था। देखें बेन वोइट के सुधार नीचे।]