कॉल स्टैक का स्थैतिक अधिकतम आकार क्यों होता है?


46

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

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

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

ऐसा क्यों है कि अधिकांश (यदि सभी नहीं) रनटाइम वातावरण आकार के लिए अधिकतम सीमा निर्धारित करते हैं, तो रनटाइम पर स्टैक बढ़ सकता है?


13
इस तरह का स्टैक निरंतर पता स्थान है जिसे चुपचाप पर्दे के पीछे नहीं ले जाया जा सकता है। पता स्थान 32 बिट सिस्टम पर मूल्यवान है।
कोडइन्चौस सिप 9'16

7
आइवरी-टॉवर विचारों की घटना को कम करने के लिए जैसे कि एकेडेमीया से बाहर निकलना और वास्तविक दुनिया में मुद्दों को कम करना जैसे कोड की पठनीयता और स्वामित्व की कुल लागत में वृद्धि;)
ब्रैड थॉमस

6
@BradThomas यही टेल कॉल ऑप्टिमाइज़ेशन है।
JAB

3
@ जॉनोवु: यह वही काम करता है जो अभी थोड़ी देर बाद करता है: स्मृति से बाहर चला जाता है।
जोर्ज डब्ल्यू मित्तग

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

जवाबों:


13

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

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

  2. जब आप उस कॉल से वापस आते हैं तो आप मूल स्टैक हद तक वापस स्थानांतरित हो जाते हैं। सबसे अधिक संभावना है कि आप एक ही धागे द्वारा भविष्य में उपयोग के लिए बनाए गए (1) को बनाए रखेंगे। सिद्धांत रूप में आप इसे जारी कर सकते हैं, लेकिन यह उस तरह से अक्षम मामलों में झूठ है जहां आप एक लूप में सीमा के पार आगे और पीछे रोकते रहते हैं, और हर कॉल के लिए मेमोरी आवंटन की आवश्यकता होती है।

  3. setjmpऔर longjmp, या गैर-स्थानीय हस्तांतरण नियंत्रण के लिए आपके ओएस के समतुल्य, जो कार्य पर हैं और आवश्यक होने पर पुराने स्टैक पर सही ढंग से वापस जा सकते हैं।

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

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

"अहा" आप कहते हैं, "ये क्या माना जाता है कि गैर-सन्निहित स्टैक्स का उपयोग करने वाले ओएस हैं? मुझे यकीन है कि यह मेरे लिए कोई उपयोग की कुछ अस्पष्ट शैक्षणिक प्रणाली है!"। खैर, यह एक और सवाल है जो सौभाग्य से पहले से ही पूछा और उत्तर दिया गया है।


36

उन डेटा संरचनाओं में आमतौर पर गुण होते हैं जो ओएस स्टैक में नहीं होते हैं:

  • लिंक की गई सूचियों के लिए प्रासंगिक पता स्थान की आवश्यकता नहीं है। इसलिए वे जब चाहें बड़े होने पर स्मृति का एक टुकड़ा जोड़ सकते हैं।

  • यहां तक ​​कि संग्रह जिन्हें सी + + सदिश की तरह सन्निहित भंडारण की आवश्यकता होती है, ओएस स्टैक पर एक फायदा होता है: वे सभी पॉइंटर्स / पुनरावृत्तियों को अमान्य घोषित कर सकते हैं जब भी वे बढ़ते हैं। दूसरी ओर, ओएस स्टैक को पॉइंट को स्टैक के लिए पॉइंटर्स को रखने की आवश्यकता होती है जब तक कि फ़ंक्शन जिसके फ्रेम का लक्ष्य रिटर्न है।

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

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


1
यह एक अच्छा जवाब है और मैं आपके अर्थ का पालन करता हूं, लेकिन "निरंतर" के विपरीत "सन्निहित" मेमोरी ब्लॉक शब्द नहीं है, क्योंकि प्रत्येक मेमोरी यूनिट का अपना अनूठा पता है?
15

2
+1 के लिए "एक कॉल स्टैक को सीमित नहीं करना पड़ता है" यह अक्सर सादगी और प्रदर्शन के लिए उस तरह से लागू किया जाता है, लेकिन यह होना जरूरी नहीं है।
पॉल ड्रेपर

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

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

26

अभ्यास में, स्टैक विकसित करना मुश्किल (और कभी-कभी असंभव) है। यह समझने के लिए कि वर्चुअल मेमोरी की कुछ समझ की आवश्यकता क्यों है।

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

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

तो एक कार्यक्रम को इसके पूर्ण पता स्थान तक पहुँच देना क्यों वांछनीय नहीं है? क्योंकि उस मेमोरी में स्वैप के खिलाफ "कमिट चार्ज" होता है; किसी भी समय या किसी एक प्रोग्राम की मेमोरी के लिए किसी अन्य प्रोग्राम की मेमोरी के लिए जगह बनाने के लिए स्वैप करने के लिए लिखना पड़ सकता है। यदि हर प्रोग्राम संभावित रूप से 2GB स्वैप का उपभोग कर सकता है, तो या तो आपको अपने सभी कार्यक्रमों के लिए पर्याप्त स्वैप प्रदान करना होगा या मौका लेना होगा कि दो कार्यक्रमों को जितना वे प्राप्त कर सकते हैं उससे अधिक की आवश्यकता होगी।

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

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

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


3
वर्तमान x86-64 CPU में केवल 48 बिट पते की जगह है
कोडइन्कॉउंस

Afaik, linux स्टैक को गतिशील रूप से विकसित करता है: जब कोई प्रक्रिया वर्तमान में आवंटित स्टैक के ठीक नीचे के क्षेत्र तक पहुंचने का प्रयास करती है, तो इस प्रक्रिया को सिगफॉल्टिंग के बजाय स्टैक मेमोरी के एक अतिरिक्त पृष्ठ को मैप करने से रुकावट को नियंत्रित किया जाता है।
9

2
@cmaster: सच है, लेकिन नहीं kdgregory "स्टैक बढ़ने" से क्या मतलब है। वर्तमान में स्टैक के रूप में उपयोग के लिए एक पता सीमा निर्धारित है। आप धीरे-धीरे उस पते सीमा में अधिक भौतिक मेमोरी को मैप करने के बारे में बात कर रहे हैं, जैसा कि इसकी आवश्यकता है। kdgregory कह रही है कि रेंज को बढ़ाना मुश्किल या असंभव है।
स्टीव जेसोप

x86 एकमात्र वास्तुकला नहीं है, और 48 बिट्स अभी भी प्रभावी रूप से अनंत है
kdgregory

1
BTW, मुझे याद है कि x86 के साथ काम करने के मेरे दिन इतने मज़ेदार नहीं थे, मुख्यतः विभाजन से निपटने की आवश्यकता के कारण। मैं MC68k प्लेटफार्मों पर परियोजनाओं को ज्यादा पसंद करता हूं ;-)
kdgregory

4

एक निश्चित अधिकतम आकार वाले स्टैक सर्वव्यापी नहीं है।

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

आप छोटी से छोटी शुरुआत करने और गतिशील रूप से बढ़ने की अनुमति देकर पहली समस्या को ठीक कर सकते हैं, लेकिन फिर भी आपको दूसरी समस्या है। और यदि आप स्टैक को गतिशील रूप से बढ़ने की अनुमति देते हैं, तो उस पर एक मनमाना सीमा क्यों डालते हैं?

ऐसी प्रणालियाँ हैं जहाँ स्टैक गतिशील रूप से विकसित हो सकते हैं और उनका अधिकतम आकार नहीं होता है: उदाहरण के लिए एरलंग, गो, स्मॉलटाक और स्कीम। कुछ को लागू करने के बहुत सारे तरीके हैं:

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

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


1

जब एक स्टैक का अनुरोध किया जाता है तो ओएस को एक सन्निहित ब्लॉक देना पड़ता है। एकमात्र तरीका यह कर सकता है कि यदि अधिकतम आकार निर्दिष्ट किया गया है।

उदाहरण के लिए, मान लें कि स्मृति अनुरोध के दौरान इस तरह दिखती है (एक्स उपयोग किए गए प्रतिनिधित्व करते हैं, ओएस अप्रयुक्त):

XOOOXOOXOOOOOX

यदि 6 के स्टैक आकार के लिए एक अनुरोध, तो ओएस जवाब उत्तर देगा, भले ही 6 से अधिक उपलब्ध हो। यदि आकार 3 के ढेर के लिए एक अनुरोध है, तो ओएस जवाब एक पंक्ति में 3 खाली स्लॉट्स (ओएस) के क्षेत्रों में से एक होगा।

इसके अलावा, किसी को अगले सन्निहित स्लॉट पर कब्जा होने पर वृद्धि की अनुमति देने में कठिनाई हो सकती है।

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

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


1

लिनक्स पर, यह विशुद्ध रूप से एक संसाधन सीमा है जो संसाधन की हानिकारक मात्रा का उपभोग करने से पहले भगोड़ा प्रक्रियाओं को मारने के लिए मौजूद है। मेरे डेबियन सिस्टम पर, निम्न कोड

#include <sys/resource.h>
#include <stdio.h>

int main() {
    struct rlimit limits;
    getrlimit(RLIMIT_STACK, &limits);
    printf("   soft limit = 0x%016lx\n", limits.rlim_cur);
    printf("   hard limit = 0x%016lx\n", limits.rlim_max);
    printf("RLIM_INFINITY = 0x%016lx\n", RLIM_INFINITY);
}

उत्पादन करता है

   soft limit = 0x0000000000800000
   hard limit = 0xffffffffffffffff
RLIM_INFINITY = 0xffffffffffffffff

ध्यान दें, यह कठिन सीमा निर्धारित है RLIM_INFINITY: इस प्रक्रिया को किसी भी राशि तक अपनी नरम सीमा बढ़ाने की अनुमति है । हालांकि, जब तक प्रोग्रामर के पास यह मानने का कोई कारण नहीं है कि प्रोग्राम को वास्तव में स्टैक मेमोरी की असामान्य मात्रा की आवश्यकता है, तो यह प्रक्रिया तब मार दी जाएगी जब यह आठ मेबिबाइट्स के स्टैक के आकार से अधिक हो जाती है।

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


तकनीकी रूप से, स्टैक गतिशील रूप से विकसित होते हैं: जब नरम-सीमा आठ मेबिबाइट पर सेट होती है, तो इसका मतलब यह नहीं है कि यह स्मृति की मात्रा वास्तव में अभी तक मैप की गई है। यह बल्कि व्यर्थ होगा क्योंकि अधिकांश कार्यक्रम कभी भी अपनी संबंधित नरम-सीमा के आस-पास नहीं मिलते हैं। इसके बजाय, कर्नेल स्टैक के नीचे एक्सेस का पता लगाएगा, और आवश्यकतानुसार मेमोरी पेजों में मैप करेगा। इस प्रकार, स्टैक आकार पर केवल वास्तविक सीमा 64 बिट सिस्टम पर उपलब्ध स्मृति है (पता स्थान विखंडन एक 16 zebibyte पता स्थान आकार के साथ सैद्धांतिक है)।


2
वह केवल पहले धागे के लिए स्टैक है। नए थ्रेड्स को नए ढेर आवंटित करने होंगे और वे सीमित हैं क्योंकि वे अन्य वस्तुओं में चलेंगे।
ज़ैन लिंक्स

0

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

वर्चुअल-मेमोरी ऑपरेटिंग सिस्टम पर ढेर वास्तव में गतिशील रूप से बढ़ते हैं, अधिकतम तक

जिसमें से बोलते हुए, यह स्थिर होने की जरूरत नहीं है। बल्कि, यह विन्यास योग्य हो सकता है, प्रति-प्रक्रिया या प्रति-थ्रेड आधार पर, यहां तक ​​कि।

यदि सवाल है " एक अधिकतम स्टैक आकार क्यों है " (एक कृत्रिम रूप से लगाया गया, आमतौर पर उपलब्ध स्मृति से बहुत कम है)?

एक कारण यह है कि अधिकांश एल्गोरिदम को ढेर सारी जगह की आवश्यकता नहीं होती है। एक बड़ा ढेर एक संभावित भगोड़ा पुनरावृत्ति का संकेत है । सभी उपलब्ध मेमोरी को आवंटित करने से पहले भगोड़ा पुनरावृत्ति को रोकना अच्छा है। एक समस्या जो भगोड़ा पुनरावृत्ति की तरह दिखती है, वह है, एक अनपेक्षित परीक्षण के मामले से उत्पन्न स्टैक का उपयोग अध: पतन। उदाहरण के लिए, मान लें कि एक बाइनरी के लिए एक पार्सर, इन्फिक्स ऑपरेटर सही ऑपरेंड पर पुनरावृत्ति करके काम करता है: पार्स फर्स्ट ऑपरैंड, स्कैन ऑपरेटर, पार्स बाकी अभिव्यक्ति। इसका मतलब है कि स्टैक की गहराई अभिव्यक्ति की लंबाई के लिए आनुपातिक है a op b op c op d ...:। इस फॉर्म के एक विशाल परीक्षण मामले में एक विशाल स्टैक की आवश्यकता होगी। जब यह एक उचित स्टैक सीमा को हिट करता है तो यह प्रोग्राम को रोक देगा।

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

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


@ लीन ने यह नहीं पूछा कि अधिकतम आकार स्थिर क्यों था, (ओं) उन्होंने पूछा कि यह पूर्वनिर्धारित क्यों था।
विल काल्डरवुड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.