"मेमोरी को संकलन के समय आवंटित किया गया" वास्तव में क्या मतलब है?


159

C और C ++ जैसी प्रोग्रामिंग भाषाओं में, लोग अक्सर स्थिर और गतिशील मेमोरी आवंटन को संदर्भित करते हैं। मैं अवधारणा को समझता हूं लेकिन "सभी स्मृति को संकलन समय के दौरान (आरक्षित) आवंटित किया गया था" हमेशा मुझे भ्रमित करता है।

संकलन, जैसा कि मैं इसे समझता हूं, उच्च स्तरीय सी / सी ++ कोड को मशीन भाषा में परिवर्तित करता है और एक निष्पादन योग्य फ़ाइल को आउटपुट करता है। संकलित फ़ाइल में मेमोरी "आवंटित" कैसे की जाती है? क्या मेमोरी हमेशा सभी वर्चुअल मेमोरी मैनेजमेंट सामान के साथ RAM में आवंटित नहीं होती है?

क्या मेमोरी का परिभाषा रनटाइम कॉन्सेप्ट से नहीं है?

अगर मैं अपने C / C ++ कोड में 1KB स्टेटिकली वेरिएबल बनाता हूं, तो क्या यह उसी राशि से निष्पादन योग्य का आकार बढ़ाएगा?

यह उन पृष्ठों में से एक है जहां वाक्यांश "स्टेटिक आवंटन" शीर्षक के तहत उपयोग किया जाता है।

बैक टू बेसिक्स: मेमोरी एलोकेशन, हिस्ट्री डाउन वॉक


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

जवाबों:


184

संकलन-समय पर आबंटित मेमोरी का अर्थ है कि संकलक संकलन-समय पर हल होता है जहां कुछ चीजें प्रक्रिया मेमोरी मैप के अंदर आवंटित की जाएंगी।

उदाहरण के लिए, एक वैश्विक सरणी पर विचार करें:

int array[100];

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

बेशक कि मेमोरी एड्रेस वर्चुअल एड्रेस हैं। कार्यक्रम मानता है कि इसकी अपनी पूरी मेमोरी स्पेस है (उदाहरण के लिए 0x00000000 से 0xFFFFFFFF तक)। इसीलिए कंपाइलर "ओके, सरणी 0x00A33211" पते पर होगा। रनटाइम के दौरान जो पते MMU और OS द्वारा वास्तविक / हार्डवेयर पते पर अनुवादित किए जाते हैं।

मूल्य इनिशियलाइज़ स्टैटिक स्टोरेज चीजें थोड़ी अलग होती हैं। उदाहरण के लिए:

int array[] = { 1 , 2 , 3 , 4 };

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

यहाँ संकलक द्वारा निर्मित असेंबली के दो उदाहरण दिए गए हैं (x86 लक्ष्य के साथ GCC4.8.1):

C ++ कोड:

int a[4];
int b[] = { 1 , 2 , 3 , 4 };

int main()
{}

आउटपुट असेंबली:

a:
    .zero   16
b:
    .long   1
    .long   2
    .long   3
    .long   4
main:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    $0, %eax
    popq    %rbp
    ret

जैसा कि आप देख सकते हैं, मानों को सीधे विधानसभा में इंजेक्ट किया जाता है। सरणी में a, संकलक 16 बाइट्स का एक शून्य आरंभीकरण उत्पन्न करता है, क्योंकि मानक कहता है कि स्थिर संग्रहीत चीजों को डिफ़ॉल्ट रूप से शून्य पर आरंभीकृत किया जाना चाहिए:

8.5.9 (प्रारंभिक) [नोट]:
स्थिर भंडारण अवधि की प्रत्येक वस्तु किसी अन्य प्रारंभिक-प्रारंभिक स्थान से पहले प्रोग्राम स्टार्टअप पर शून्य-आरंभीकृत होती है। कुछ मामलों में, बाद में अतिरिक्त इनिशियलाइज़ेशन किया जाता है।

मैं हमेशा लोगों को अपने कोड को डिसाइड करने के लिए सुझाव देता हूं कि कंपाइलर वास्तव में C ++ कोड के साथ क्या करता है। यह उन्नत संकलक अनुकूलन के लिए भंडारण वर्गों / अवधि (इस प्रश्न की तरह) से लागू होता है। आप अपने कंपाइलर को असेंबली जेनरेट करने के लिए निर्देश दे सकते हैं, लेकिन इंटरनेट पर एक दोस्ताना तरीके से ऐसा करने के लिए अद्भुत उपकरण हैं। मेरा पसंदीदा जीसीसी एक्सप्लोरर है


2
धन्यवाद। यह बहुत कुछ स्पष्ट करता है। इसलिए कंपाइलर "रिजर्व मेमोरी को 0xABC से 0xXYZ तक वेरिएबल एरे [] आदि के लिए कुछ बराबर करता है।" और फिर लोडर का उपयोग करता है कि वास्तव में यह कार्यक्रम चलाने से ठीक पहले इसे आवंटित करता है?
तल्हा सईद

1
@ तालशेद बिल्कुल उदाहरण देखने के लिए संपादन देखें
Manu343726

2
@Secko मैंने चीजों को सरल बनाया है। कार्यक्रम के बारे में इसका केवल एक उल्लेख वर्चुअल मेमोरी के माध्यम से काम करता है, लेकिन जैसा कि सवाल वर्चुअल मेमोरी के बारे में नहीं है, मैंने विषय को नहीं बढ़ाया है। मैं केवल इशारा कर रहा था कि कंपाइलर मेमोरी मेमोरी एड्रेस के बारे में मान्यताओं को कर सकता है, वर्चुअल मेमोरी के लिए धन्यवाद।
मनु ३४३ Man२६

2
@ साइको हां। एमएमएम "उत्पन्न" एक बेहतर शब्द है जो मुझे लगता है।
मनु ३४३ Man२६

2
"इसकी प्रक्रिया मेमोरी स्पेस के स्टैटिक मैमोरी क्षेत्र में आवंटित की गई" रीडिंग जिसने मेरी प्रक्रिया मेमोरी स्पेस में कुछ स्थिर मैमोरी क्षेत्रों को आवंटित किया।
रेडियोडेफ

27

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

क्या मेमोरी का परिभाषा रनटाइम कॉन्सेप्ट से नहीं है?

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

अगर मैं अपने C / C ++ कोड में 1KB स्टेटिकली वेरिएबल बनाता हूं, तो क्या यह उसी राशि से निष्पादन योग्य का आकार बढ़ाएगा?

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


1
अगर मैं लिखता हूं तो static int i[4] = {2 , 3 , 5 ,5 }यह निष्पादन योग्य आकार में 16 बाइट्स तक बढ़ जाएगा। आपने कहा "बस स्टैटिक की घोषणा करने से आपके निष्पादन योग्य आकार में कुछ बाइट्स से अधिक वृद्धि नहीं होगी। इसे प्रारंभिक मूल्य के साथ घोषित करना गैर-शून्य इच्छाशक्ति है" इसे प्रारंभिक मूल्य के साथ घोषित करना इसका मतलब क्या होगा।
सूरज जैन

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

इसे लागू करने के रूप में परिभाषित किया गया है कि यह कहाँ रखा गया है / इसे कैसे आवंटित किया जाता है, लेकिन मुझे यकीन नहीं है कि मुझे पता होना चाहिए।
महिंद्रा

23

संकलित समय में मेमोरी का मतलब है कि जब आप प्रोग्राम को लोड करते हैं, तो मेमोरी का कुछ हिस्सा तुरंत आवंटित किया जाएगा और संकलन के समय पर इस आवंटन का आकार (सापेक्ष) निर्धारित किया जाता है।

char a[32];
char b;
char c;

उन 3 चर को "संकलन समय पर आवंटित" किया जाता है, इसका मतलब है कि संकलनकर्ता संकलन समय पर उनके आकार (जो तय हो गया है) की गणना करता है। चर aस्मृति में एक ऑफसेट होगा, मान लें कि पता 0 की ओर इशारा करते हुए, b33 पते cपर और 34 पर इंगित करेगा (कोई संरेखण अनुकूलन नहीं)। इसलिए, स्थैतिक डेटा का 1Kb आवंटित करने से आपके कोड का आकार नहीं बढ़ेगा , क्योंकि यह बस इसके अंदर एक ऑफसेट को बदल देगा। वास्तविक स्थान को लोड समय पर आवंटित किया जाएगा

वास्तविक मेमोरी आवंटन हमेशा रन टाइम में होता है, क्योंकि कर्नेल को इसका ट्रैक रखने और इसकी आंतरिक डेटा संरचनाओं को अपडेट करने की आवश्यकता होती है (प्रत्येक प्रक्रिया, पृष्ठों और इतने पर कितनी मेमोरी आवंटित की जाती है)। अंतर यह है कि संकलक पहले से ही आपके द्वारा उपयोग किए जा रहे प्रत्येक डेटा का आकार जानता है और जैसे ही आपके प्रोग्राम को निष्पादित किया जाता है, उसे आवंटित किया जाता है।

यह भी याद रखें कि हम रिश्तेदार पते के बारे में बात कर रहे हैं । वास्तविक पता जहां चर स्थित होगा वह अलग होगा। लोड के समय कर्नेल प्रक्रिया के लिए कुछ मेमोरी आरक्षित करेगा, पते पर कह सकता है x, और निष्पादन योग्य फ़ाइल में निहित सभी हार्ड कोडित पते xबाइट्स द्वारा बढ़ाए जाएंगे , ताकि aउदाहरण में चर पते पर होगाx , पते पर ख x+33और जल्द ही।


17

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

यदि 1k एक स्ट्रिंग है, एक हजार वर्णों का, जो ऐसा घोषित किया जाता है

const char *c_string = "Here goes a thousand chars...999";//implicit \0 at end

और आप तब थे vim your_compiled_bin, आप वास्तव में उस स्ट्रिंग को बिन में देख पाएंगे। उस मामले में, हाँ: निष्पादन योग्य 1 k बड़ा होगा, क्योंकि इसमें स्ट्रिंग पूर्ण है।
यदि, हालांकि, आप स्टैक पर ints, chars या longs की एक सरणी आवंटित करते हैं और इसे लूप में असाइन करते हैं, तो इन पंक्तियों के साथ कुछ

int big_arr[1000];
for (int i=0;i<1000;++i) big_arr[i] = some_computation_func(i);

तब, नहीं: यह बिन में वृद्धि नहीं करेगा ... 1000*sizeof(int)
संकलन समय पर आवंटन से इसका मतलब है कि अब आप इसे समझने के लिए आए हैं इसका मतलब है (आपकी टिप्पणियों के आधार पर): संकलित बिन में वह जानकारी होती है, जिसमें सिस्टम को यह जानना होता है कि मेमोरी कितनी है स्टैक के आकार की जानकारी के साथ-साथ आपके आवेदन की आवश्यकता होने पर किस फ़ंक्शन / ब्लॉक की आवश्यकता होगी। जब यह आपके बिन को निष्पादित करता है, तो सिस्टम आवंटित करेगा, और आपका कार्यक्रम एक प्रक्रिया बन जाता है (ठीक है, आपके बिन का निष्पादन प्रक्रिया है ... ठीक है, आपको वही मिलता है जो मैं कह रहा हूं)।
बेशक, मैं यहां पूरी तस्वीर नहीं चित्रित कर रहा हूं: बिन में इस बात की जानकारी है कि बिन वास्तव में कितना बड़ा स्टैक होगा। इस जानकारी (अन्य चीजों के बीच) के आधार पर, सिस्टम मेमोरी का एक हिस्सा आरक्षित करेगा, जिसे स्टैक कहा जाता है, जो कि प्रोग्राम को मुफ्त शासन से अलग हो जाता है। स्टैक मेमोरी अभी भी सिस्टम द्वारा आवंटित की जाती है, जब प्रक्रिया (आपके बिन निष्पादित होने का परिणाम) शुरू की जाती है। प्रक्रिया तब आपके लिए स्टैक मेमोरी का प्रबंधन करती है। जब कोई फ़ंक्शन या लूप (किसी भी प्रकार का ब्लॉक) लागू होता है / निष्पादित हो जाता है, तो उस ब्लॉक के स्थानीय चर स्टैक पर धकेल दिए जाते हैं, और उन्हें हटा दिया जाता है (स्टैक मेमोरी "फ्रीड" होती है इसलिए बोलने के लिए) अन्य द्वारा उपयोग की जाने वाली कार्य / ब्लॉक। इसलिए घोषित कर रहे हैंint some_array[100]केवल बिन में अतिरिक्त जानकारी के कुछ बाइट्स जोड़ देगा, जो सिस्टम को बताता है कि फ़ंक्शन X को 100*sizeof(int)कुछ बुक-कीपिंग स्पेस अतिरिक्त की आवश्यकता होगी ।


बहुत बहुत धन्यवाद। एक और सवाल, क्या संकलन के समय कार्यों के लिए स्थानीय चर भी उसी तरह आवंटित किए जाते हैं?
तलहा सईद

@ तालशायड: हाँ, इसका मतलब है कि जब मैंने कहा था: "जानकारी के लिए सिस्टम को यह जानना आवश्यक है कि फ़ंक्शन / ब्लॉक को कितनी मेमोरी की आवश्यकता होगी।" जिस क्षण आप एक फ़ंक्शन को कॉल करते हैं, सिस्टम उस फ़ंक्शन के लिए आवश्यक मेमोरी आवंटित करेगा। जिस क्षण फ़ंक्शन वापस आता है, उस मेमोरी को फिर से मुक्त कर दिया जाएगा।
इलायस वान ओटगेम

आपके सी कोड में टिप्पणियों के लिए: यह वास्तव में / जरूरी नहीं है कि क्या होता है। उदाहरण के लिए, संकलित समय पर स्ट्रिंग को केवल एक बार आवंटित किया जाएगा। इस प्रकार यह कभी भी "मुक्त" नहीं होता (मुझे भी लगता है कि शब्दावली का उपयोग आमतौर पर केवल तब किया जाता है जब आप गतिशील रूप से कुछ आवंटित करते हैं), i"मुक्त" या तो नहीं होता है। यदि iस्मृति पर निवास किया जाता है, तो यह केवल स्टैक पर धकेल दिया जाएगा, ऐसा कुछ जिसे शब्द के उस अर्थ में मुक्त नहीं किया गया है, जो उस समय की अवहेलना करता है iया cपूरे समय रजिस्टर में रखा जाएगा। बेशक, यह सब संकलक पर निर्भर करता है, जिसका अर्थ है कि यह काला और सफेद नहीं है।
प्रेत ०५

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

ओह समझा। उस मामले में मेरी टिप्पणी का अर्थ यह है कि "मैं आपके शब्दों से भ्रमित था।"
प्रेत ०५

16

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

int a;
const int b[6] = {1,2,3,4,5,6};
char c[200];
const int d = 23;
int e[4] = {1,2,3,4};
int f;

यह लिंकर को बताएगा कि उसे bss के लिए 208 बाइट्स, "डेटा" के लिए 16 बाइट्स और "कॉन्स्ट" के लिए 28 बाइट्स की आवश्यकता थी। इसके अलावा, एक चर के लिए किसी भी संदर्भ को एक क्षेत्र चयनकर्ता और ऑफसेट के साथ बदल दिया जाएगा, इसलिए a, b, c, d और e को bss + 0, const + 0, bss + 4, const + 24, डेटा से बदल दिया जाएगा +0, या bss + 204, क्रमशः।

जब कोई प्रोग्राम लिंक किया जाता है, तो सभी मॉड्यूल के सभी bss क्षेत्रों को एक साथ सम्‍मिलित किया जाता है; इसी तरह डेटा और कास्ट क्षेत्रों। प्रत्येक मॉड्यूल के लिए, किसी भी bss- सापेक्ष चर का पता सभी पूर्ववर्ती मॉड्यूल के bss क्षेत्रों (फिर से, डेटा और कॉन्स्ट के साथ) के आकार से बढ़ाया जाएगा। इस प्रकार, जब लिंकर किया जाता है, तो किसी भी कार्यक्रम में एक बीएसएस आवंटन, एक डेटा आवंटन और एक कॉन्स्टेबल आवंटन होगा।

जब कोई प्रोग्राम लोड होता है, तो चार में से एक चीज आमतौर पर प्लेटफॉर्म के आधार पर होती है:

  1. निष्पादन योग्य इंगित करेगा कि आरंभिक डेटा क्षेत्र के लिए, जहां प्रारंभिक सामग्री मिल सकती है, प्रत्येक प्रकार के डेटा के लिए और - कितने बाइट्स की आवश्यकता है। इसमें उन सभी निर्देशों की एक सूची भी शामिल होगी जो bss-, data-, या const- सापेक्ष पते का उपयोग करते हैं। ऑपरेटिंग सिस्टम या लोडर प्रत्येक क्षेत्र के लिए उचित मात्रा में स्थान आवंटित करेगा और फिर प्रत्येक निर्देश के लिए उस क्षेत्र का शुरुआती पता जोड़ देगा।

  2. ऑपरेटिंग सिस्टम तीनों प्रकार के डेटा को रखने के लिए मेमोरी का एक हिस्सा आवंटित करेगा, और एप्लिकेशन को मेमोरी के उस हिस्से को एक पॉइंटर देगा। कोई भी कोड जो स्थैतिक या वैश्विक डेटा का उपयोग करता है, वह उस सूचक के सापेक्ष इसे घटा देगा (कई मामलों में, सूचक को किसी एप्लिकेशन के जीवन भर के लिए रजिस्टर में संग्रहीत किया जाएगा)।

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

  4. ऑपरेटिंग सिस्टम शुरू में आवेदन के लिए स्थान आवंटित नहीं करेगा, लेकिन एप्लिकेशन स्टार्टअप पर (जैसा कि ऊपर) एक उपयुक्त आवंटन का अनुरोध करेगा। एप्लिकेशन में उन पते के साथ निर्देशों की एक सूची शामिल होगी, जिन्हें यह प्रतिबिंबित करने के लिए अद्यतन करने की आवश्यकता है कि स्मृति को कहाँ आवंटित किया गया था (पहली शैली के साथ), लेकिन इसके बजाय ओएस लोडर द्वारा पैच किए गए आवेदन के बजाय, आवेदन में खुद को पैच करने के लिए पर्याप्त कोड शामिल होगा। ।

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


13

आपके प्रश्न का मूल यह है: "संकलित फ़ाइल में मेमोरी" कैसे "आवंटित की गई है? क्या रैम हमेशा सभी वर्चुअल मेमोरी मैनेजमेंट सामान के साथ RAM में आवंटित नहीं होती है? क्या रनटाइम कॉन्सेप्ट की परिभाषा से मेमोरी आवंटन नहीं है?"

मुझे लगता है कि समस्या यह है कि मेमोरी आवंटन में दो अलग-अलग अवधारणाएं शामिल हैं। इसके मूल में, मेमोरी आवंटन वह प्रक्रिया है जिसके द्वारा हम कहते हैं कि "डेटा का यह आइटम मेमोरी के इस विशिष्ट भाग में संग्रहीत है"। एक आधुनिक कंप्यूटर सिस्टम में, इसमें दो चरण की प्रक्रिया शामिल है:

  • कुछ सिस्टम का उपयोग वर्चुअल पते को तय करने के लिए किया जाता है, जिस पर आइटम संग्रहीत किया जाएगा
  • वर्चुअल एड्रेस को फिजिकल एड्रेस पर मैप किया जाता है

बाद की प्रक्रिया विशुद्ध रूप से चलने का समय है, लेकिन पूर्व संकलन समय पर किया जा सकता है, यदि डेटा का ज्ञात आकार है और उनमें से एक निश्चित संख्या की आवश्यकता है। यहाँ मूल रूप से यह कैसे काम करता है:

  • कंपाइलर एक स्रोत फ़ाइल देखता है जिसमें एक पंक्ति होती है जो इस तरह से दिखाई देती है:

    int c;
  • यह कोडांतरक के लिए आउटपुट का उत्पादन करता है जो इसे चर 'c' के लिए मेमोरी आरक्षित करने का निर्देश देता है। यह इस तरह लग सकता है:

    global _c
    section .bss
    _c: resb 4
  • जब असेम्बलर चलता है, तो यह एक काउंटर रखता है जो प्रत्येक आइटम को मेमोरी 'सेगमेंट' (या 'सेक्शन') की शुरुआत से ट्रैक करता है। यह एक बहुत बड़ी 'संरचना' के हिस्सों की तरह है जिसमें पूरी फ़ाइल में वह सब कुछ है जो इस समय इसके लिए आवंटित कोई वास्तविक मेमोरी नहीं है, और कहीं भी हो सकता है। यह एक ऐसी तालिका में नोट करता है _cजिसमें एक विशेष ऑफसेट होता है (खंड की शुरुआत से 510 बाइट्स कहें) और फिर इसके काउंटर को 4 से बढ़ाता है, इसलिए अगला ऐसा वैरिएबल होगा (जैसे) 514 बाइट्स। ऐसे किसी भी कोड के लिए _c, जिसके पते की जरूरत है , यह सिर्फ 510 को आउटपुट फ़ाइल में रखता है, और एक नोट जोड़ता है कि आउटपुट को उस सेगमेंट के पते की आवश्यकता होती है, जिसमें _cबाद में इसे जोड़ा जाता है।

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

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


9

एक निष्पादन योग्य वर्णन करता है कि स्थिर चर के लिए क्या स्थान आवंटित किया जाए। यह आवंटन सिस्टम द्वारा किया जाता है, जब आप निष्पादन योग्य चलाते हैं। तो आपका 1kB स्टैटिक वेरिएबल 1kB के साथ निष्पादन योग्य का आकार नहीं बढ़ाएगा:

static char[1024];

जब तक आप एक इनिशलाइज़र निर्दिष्ट नहीं करते हैं:

static char[1024] = { 1, 2, 3, 4, ... };

तो, 'मशीन भाषा' (यानी सीपीयू निर्देश) के अलावा, एक निष्पादन योग्य में आवश्यक मेमोरी लेआउट का विवरण होता है।


5

मेमोरी को कई तरीकों से आवंटित किया जा सकता है:

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

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

लेकिन ज्यादातर मामलों में व्यक्ति केवल यह कहना चाहता है कि आवंटित की जाने वाली स्मृति की मात्रा को संकलन समय पर जाना जाता है

बाइनरी साइज़ तभी बदलेगा जब मेमोरी आपके ऐप के कोड या डेटा सेगमेंट में आरक्षित होगी।


1
यह उत्तर भ्रमित करने वाला (या भ्रमित) है कि यह "एप्लिकेशन हीप", "ओएस हीप", और "जीसी हीप" के बारे में बात करता है जैसे कि ये सभी सार्थक अवधारणाएं थीं। मुझे लगता है कि # 1 से आप यह कहने की कोशिश कर रहे थे कि कुछ प्रोग्रामिंग लैंग्वेज (काल्पनिक रूप से) एक "हीप एलोकेशन" स्कीम का उपयोग कर सकती हैं, जो कि .data सेक्शन में निश्चित आकार के बफर से मेमोरी को आवंटित करती है, लेकिन यह अवास्तविक रूप से हानिकारक होने के लिए पर्याप्त है। ओपी की समझ में। # 2 और # 3, जीसी की उपस्थिति वास्तव में कुछ भी नहीं बदलती है। और # 5 फिर से, आपने अपेक्षाकृत MUCH के बीच .dataऔर अधिक महत्वपूर्ण अंतर छोड़ दिया .bss
क्क्सप्लसोन

4

तुम सही हो। मेमोरी वास्तव में लोड समय पर (पृष्ठांकित) आवंटित की जाती है, यानी जब निष्पादन योग्य फ़ाइल को (आभासी) मेमोरी में लाया जाता है। उस क्षण भी स्मृति को आरंभ किया जा सकता है। कंपाइलर सिर्फ मेमोरी मैप बनाता है। [वैसे, स्टैक और हीप स्थान भी लोड समय पर आवंटित किए जाते हैं!]


2

मुझे लगता है कि आपको थोड़ा पीछे हटने की जरूरत है। संकलन के समय आवंटित की गई मेमोरी .... इसका क्या मतलब हो सकता है? क्या इसका मतलब यह हो सकता है कि चिप्स पर मेमोरी जो अभी तक निर्मित नहीं हुई है, उन कंप्यूटरों के लिए जो अभी तक डिज़ाइन नहीं किए गए हैं, किसी तरह आरक्षित किया जा रहा है? नहीं, समय यात्रा, कोई संकलक जो ब्रह्मांड में हेरफेर कर सकता है।

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


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

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

@Quuxplusone: क्षमा करें, अगर मैं यहां झूठे आरोप लगा रहा हूं, लेकिन मुझे लगता है कि आप उन लोगों में से एक थे, जिन्होंने मेरे उत्तर को भी स्वीकार किया था। यदि ऐसा है, तो क्या आप इस बात की ओर ध्यान दिलाएंगे कि मेरे उत्तर का कौन सा भाग ऐसा करने का मुख्य कारण था, और क्या आप अपने संपादन की जाँच करना चाहेंगे? मुझे पता है कि मैंने स्टैक मेमोरी को कैसे प्रबंधित किया जाता है, इसके सही आंतरिक के बारे में कुछ अंशों को छोड़ दिया है, इसलिए मैंने अब अपने उत्तर के बारे में 100% सटीक नहीं होने के बारे में थोड़ा सा जोड़ा है :)
एलियास वान ओओटगेम

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

2

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

इसलिए यदि आपका डेटा खंड 500 बाइट्स का है, तो आपके प्रोग्राम में 500 बाइट क्षेत्र है। यदि आप डेटा खंड को 1500 बाइट्स में बदलते हैं, तो प्रोग्राम का आकार 1000 बाइट्स बड़ा हो जाएगा। डेटा को वास्तविक कार्यक्रम में इकट्ठा किया जाता है।

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


2

मैं कुछ आरेखों की मदद से इन अवधारणाओं की व्याख्या करना चाहता हूं।

यह सच है कि मेमोरी को संकलन समय पर, निश्चित रूप से आवंटित नहीं किया जा सकता है। लेकिन, फिर संकलन के समय वास्तव में क्या होता है।

यहाँ स्पष्टीकरण आता है। उदाहरण के लिए, एक प्रोग्राम के चार चर हैं x, y, z और k। अब, संकलन के समय यह केवल एक मेमोरी मैप बनाता है, जहां एक दूसरे के संबंध में इन चरों के स्थान का पता लगाया जाता है। यह आरेख इसे बेहतर रूप से चित्रित करेगा।

अब कल्पना कीजिए, कोई कार्यक्रम स्मृति में नहीं चल रहा है। यह मैं एक बड़ी खाली आयत से दिखाता हूँ।

खाली जगह

अगला, इस कार्यक्रम का पहला उदाहरण निष्पादित किया गया है। आप इसकी कल्पना इस प्रकार कर सकते हैं। यह वह समय है जब वास्तव में मेमोरी आवंटित की जाती है।

पहला उदहारण

जब इस कार्यक्रम का दूसरा उदाहरण चल रहा है, तो मेमोरी निम्नानुसार दिखाई देगी।

दूसरा उदाहरण

और तीसरा ।।

तीसरा उदाहरण

इसी तरह आगे भी।

मुझे उम्मीद है कि यह दृश्य इस अवधारणा को अच्छी तरह से समझाता है।


2
यदि उन आरेखों ने स्थिर और गतिशील स्मृति के बीच अंतर दिखाया तो वे अधिक उपयोगी IMHO होंगे।
बार्टेक बानचेविच 10

चीजों को सरल रखने के लिए मेरे द्वारा जानबूझकर इसे टाला गया था। मेरा ध्यान ज्यादा तकनीकी अव्यवस्था के बिना स्पष्टता के साथ इस फन्दे को समझाना है। जहाँ तक यह स्थैतिक चर के लिए है .. इस बिंदु को पिछले उत्तरों द्वारा अच्छी तरह से स्थापित किया गया है। इसलिए मैंने इसे छोड़ दिया है।
user3258051

1
एह, यह अवधारणा विशेष रूप से जटिल नहीं है, इसलिए मैं नहीं देखता कि इसे बनाने की तुलना में इसे सरल क्यों बनाया जाए, लेकिन चूंकि इसका मतलब केवल प्रशंसात्मक उत्तर के रूप में है, ठीक है।
बार्टेक बैनचेविज़

1

स्वीकृत उत्तर में बहुत अच्छी व्याख्या दी गई है। बस के मामले में मैं लिंक है जो मैं उपयोगी पाया है पोस्ट करेंगे। https://www.tenouk.com/ModuleW.html

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.