स्टैक मेमोरी साइज़ इतना सीमित क्यों है?


85

जब आप ढेर पर मेमोरी आवंटित करते हैं, तो एकमात्र सीमा मुफ्त रैम (या वर्चुअल मेमोरी) है। यह मेमोरी की Gb बनाता है।

तो स्टैक का आकार इतना सीमित (लगभग 1 एमबी) क्यों है? क्या तकनीकी कारण आपको स्टैक पर वास्तव में बड़ी वस्तुओं को बनाने से रोकता है?

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


ढेर पर बड़ी वस्तुएं बनाना व्यावहारिक क्यों होगा? (कॉल चेन आमतौर पर स्टैक पर जाती हैं।)
मोटो

4
मुझे लगता है कि वास्तविक उत्तर अधिकांश उत्तरों की तुलना में सरल है: "क्योंकि यह है कि हमने हमेशा इसे कैसे किया है, और यह अभी तक ठीक है इसलिए बदलाव क्यों?"
जेरी कॉफिन

@JerryCoffin क्या आपने अब तक पोस्ट किए गए किसी भी उत्तर को पढ़ा है? इस प्रश्न में अधिक अंतर्दृष्टि है।
user1202136

3
@ user1202136: मैंने उन सभी को पढ़ा है - लेकिन लोग अनुमान लगा रहे हैं, और मेरा अनुमान है कि वे जिन कारकों का हवाला दे रहे हैं, उनमें से शायद इस विषय पर मूल निर्णय लेने में भी विचार नहीं किया गया था। एक वाक्यांश को सिक्का करने के लिए, "कभी-कभी सिगार केवल सिगार होता है।"
जेरी कॉफिन

3
"हमें कितना बड़ा स्टैक बनाना चाहिए?" "ओह, मुझे पता नहीं, हम कितने धागे चला सकते हैं?" "यह एक K के ऊपर कहीं उड़ता है" "ठीक है, फिर, हम इसे 2K कहेंगे, हमें 2 गिग ऑफ़ वर्चुअल मिला है, तो यह कितना मेगा है?" "हाँ, ठीक है, अगला मुद्दा क्या है?"
मार्टिन जेम्स

जवाबों:


46

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

उदाहरण के लिए, एक 32-बिट एप्लिकेशन में आम तौर पर 2GB का वर्चुअल एड्रेस स्पेस होता है। इसका मतलब है कि यदि स्टैक का आकार 2 एमबी (pthreads में डिफ़ॉल्ट रूप में) है, तो आप अधिकतम 1024 थ्रेड बना सकते हैं। यह वेब सर्वर जैसे अनुप्रयोगों के लिए छोटा हो सकता है। स्टैक का आकार बढ़ाते हुए, 100 एमबी (यानी, आप 100 एमबी आरक्षित करते हैं, लेकिन जरूरी नहीं कि स्टैक को तुरंत 100MB आवंटित किया गया हो), थ्रेड्स की संख्या को लगभग 20 तक सीमित कर देगा, जो कि साधारण GUI अनुप्रयोगों के लिए भी सीमित हो सकता है।

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


कई 64-बिट मशीनों में केवल 48-बिट पते हैं (32-बिट पर एक बड़ा लाभ दिया गया है, लेकिन अभी भी सीमित है)। अतिरिक्त स्थान के साथ भी आपको यह चिंता करनी होगी कि पृष्ठ तालिकाओं के संबंध में आरक्षण - यानी अधिक स्थान होने पर हमेशा ओवरहेड होता है। यह शायद केवल एक सस्ते के रूप में है, यदि सस्ता नहीं है, तो प्रत्येक थ्रेड के लिए विशाल स्टैक रिक्त स्थान के बजाय एक नया खंड (एमएमएपी) आवंटित करने के लिए।
eda-qa mort-ora-y

4
@ edA-qamort-ora-y: यह उत्तर आवंटन के बारे में बात नहीं कर रहा है , यह आभासी मेमोरी पुनर्जीवन के बारे में बात कर रहा है , जो लगभग मुफ्त है, और निश्चित रूप से मिमीप की तुलना में बहुत तेज़ है।
मूइंग डक

33

एक पहलू जो किसी ने अभी तक उल्लेख नहीं किया है:

एक सीमित स्टैक आकार एक त्रुटि का पता लगाने और रोकथाम तंत्र है।

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

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


आपके पास आबंटित ऑब्जेक्ट के साथ समान समस्या हो सकती है (जैसा कि पुनरावर्तन को बदलने का कोई तरीका मैन्युअल रूप से स्टैक को संभालना है)। यह सीमा अन्य तरीकों का उपयोग करने के लिए मजबूर करती है (जो आवश्यक सुरक्षित / सरल / / नहीं हैं) (नोट (खिलौना के बारे में टिप्पणी की संख्या को नोट करें) std::unique_ptrएक विनाशकारी (और स्मार्ट पॉइंटर पर निर्भर नहीं ) लिखने के साथ कार्यान्वयन ।
जारोड42

15

यह सिर्फ एक डिफ़ॉल्ट आकार है। यदि आपको अधिक आवश्यकता है, तो आप अतिरिक्त स्टैक स्थान आवंटित करने के लिए लिंकर को बताकर अधिक बार प्राप्त कर सकते हैं।

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

आपको अपने कार्यक्रम के लिए उचित संतुलन खोजना होगा।


@BJovke जैसे कुछ लोगों का मानना ​​है कि वर्चुअल मेमोरी अनिवार्य रूप से मुफ्त है। यह सच है कि आपको सभी वर्चुअल मेमोरी का समर्थन करने के लिए भौतिक मेमोरी की आवश्यकता नहीं है। आपको वर्चुअल मेमोरी को कम से कम एड्रेस देने में सक्षम होना चाहिए।

हालांकि, एक विशिष्ट 32-बिट पीसी पर वर्चुअल मेमोरी का आकार भौतिक मेमोरी के आकार के समान है - क्योंकि हमारे पास किसी भी पते, वर्चुअल या नहीं के लिए केवल 32 बिट्स हैं।

क्योंकि प्रक्रिया में सभी थ्रेड्स समान पता स्थान साझा करते हैं, इसलिए उन्हें इसे उनके बीच विभाजित करना होगा। और ऑपरेटिंग सिस्टम ने अपना हिस्सा लेने के बाद एक आवेदन के लिए "केवल" 2-3 जीबी छोड़ दिया है। और वह आकार भौतिक और आभासी मेमोरी दोनों के लिए सीमा है , क्योंकि वहाँ कोई और पते नहीं हैं।


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

2
@MartinJames: कोई भी यह नहीं कह रहा है कि सभी वस्तुओं को स्टैक पर होना चाहिए, हम चर्चा कर रहे हैं कि डिफ़ॉल्ट स्टैक का आकार छोटा क्यों है।
मूइंग डक

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

1
@BJovke - लेकिन वर्चुअल एड्रेस स्पेस अभी भी उपयोग किया जाएगा। 32-बिट प्रक्रिया में यह कुछ जीबी तक सीमित है, इसलिए केवल 20 * 100MB को जला देने से आपको समस्या होगी।
बो पर्सन

7

एक बात के लिए, स्टैक निरंतर है, इसलिए यदि आप 12MB आवंटित करते हैं, तो आपको जो कुछ भी आपके द्वारा बनाया जाना चाहिए नीचे जाने पर 12MB निकालना होगा। इसके अलावा वस्तुओं के चारों ओर घूमना बहुत कठिन हो जाता है। यहाँ एक वास्तविक दुनिया उदाहरण है जो चीजों को समझने में आसान बना सकता है:

कहते हैं कि आप एक कमरे के चारों ओर बक्से खड़ी कर रहे हैं। जिसे प्रबंधित करना आसान है:

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

वे दो उदाहरण सकल सामान्यीकरण हैं और कुछ बिंदु हैं जो सादृश्य में स्पष्ट रूप से गलत हैं लेकिन यह काफी करीब है कि यह उम्मीद है कि आपको दोनों मामलों में फायदे देखने में मदद मिलेगी।


@MooingDuck हां, लेकिन आप अपने प्रोग्राम में वर्चुअल मेमोरी में काम कर रहे हैं, अगर मैं एक सबरूटीन में प्रवेश करता हूं, तो स्टैक पर कुछ डालूं, फिर सबरूटीन से वापस आऊंगा या मुझे लेट जाने से पहले ऑब्जेक्ट को डी-आवंटित या स्थानांतरित करने की आवश्यकता होगी मैं जहाँ से आया था वहाँ वापस आने के लिए ढेर।
स्कॉट चैंबरलेन

1
हालांकि मेरी टिप्पणी एक गलत व्याख्या के कारण थी (और मैंने इसे हटा दिया), मैं अभी भी इस जवाब से सहमत नहीं हूं। स्टैक के शीर्ष पर 12MB को हटाना शाब्दिक रूप से एक opcode है। यह मूल रूप से स्वतंत्र है। कंपाइलर "स्टैक" नियम को धोखा दे सकते हैं, इसलिए नहीं, उन्हें इसे वापस करने के लिए तैयार करने से पहले ऑब्जेक्ट को कॉपी / स्थानांतरित करने की आवश्यकता नहीं है। इसलिए मुझे लगता है कि आपकी टिप्पणी भी गलत है।
मूइंग डक

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

@MartinJames: C ++ कल्पना यह भी कहती है कि फ़ंक्शन आमतौर पर डेटा को सीधे गंतव्य बफर में डाल सकता है और अस्थायी का उपयोग नहीं कर सकता है, इसलिए यदि आप सावधान हैं, तो मूल्य से 12MB बफर वापस करने के लिए कोई ओवरहेड नहीं है।
मूइंग डक

4

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

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

इसलिए यह पुराने समय से ही नहीं बल्कि प्रदर्शन के लिए एक अच्छा प्रतिमान है।


4
जबकि मेरा मानना ​​है कि स्टैकिंग आकार को कृत्रिम रूप से कम करने के कारण कैशिंग एक बड़ी भूमिका निभाता है, मुझे आपको "ढेर पर ढेर जीवन" वाले बयान पर सही करना होगा। स्टैक और हीप दोनों मेमोरी में रहते हैं (वस्तुतः या शारीरिक रूप से)।
सेबेस्टियन होजस

एक्सेस स्पीड से संबंधित "निकट या दूर" कैसा है?
मिन्ह नगूना

@ MinNgh ca खैर, RAM में चर L2 मेमोरी में कैश हो जाते हैं, फिर L1 मेमोरी में कैश किया जाता है, और फिर रजिस्टरों में भी कैश हो जाता है। RAM तक पहुंच धीमी है, L2 तक तेज है, L1 अभी भी तेज है, और रजिस्टर सबसे तेज है। मुझे लगता है कि ओपी का मतलब यह है कि स्टैक में संग्रहीत चर को जल्दी से एक्सेस किया जाना चाहिए, इसलिए सीपीयू स्टैक चर को अपने पास रखने की पूरी कोशिश करेगा, इसलिए आप इसे छोटा बनाना चाहते हैं, इसलिए सीपीयू तेजी से चर का उपयोग कर सकता है।
157 239n

1

आपको लगता है कि कई चीजों के लिए आपको एक बड़ा स्टैक चाहिए, कुछ अन्य तरीके से किया जा सकता है।

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

(मैं पास्कल में दिए गए एल्गोरिदम के साथ दूसरे संस्करण का पक्ष लेता हूं। इसका इस्तेमाल आठ रुपये में किया जा सकता है।)

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


-8

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


1
कोई भी यह नहीं कह रहा है कि सभी वस्तुओं को स्टैक पर होना चाहिए, हम चर्चा कर रहे हैं कि डिफ़ॉल्ट स्टैक का आकार छोटा क्यों है।
मूइंग डक

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

3
एक फ़ंक्शन कॉल। int main() { char buffer[1048576]; } यह एक बहुत ही आम नौसिखिया समस्या है। सुनिश्चित करें कि एक आसान समाधान है, लेकिन हमें स्टैक आकार को क्यों हल करना चाहिए?
मूइंग डक

खैर, एक बात के लिए, मैं 12MB (या वास्तव में, 1MB) चाहता हूं, पीडित फ़ंक्शन को कॉल करने वाले प्रत्येक थ्रेड के स्टैक पर लगाई गई स्टैक आवश्यकता की। उन्होंने कहा, मुझे इस बात से सहमत होना होगा कि 1MB थोड़ा कंजूस है। मैं एक डिफ़ॉल्ट 100 एमबी के साथ खुश होऊंगा, आखिरकार, कुछ भी नहीं है जो मुझे रोक रहा है इसे 128K करने के लिए बस उसी तरह से बदल रहा है जैसे कि अन्य डेवलपर्स को इसे बंद करने से कुछ भी नहीं रोक रहा है।
मार्टिन जेम्स Martin

1
आप अपने धागे पर 12MB का ढेर क्यों नहीं लगाना चाहेंगे? इसका एकमात्र कारण यह है कि ढेर छोटे होते हैं। यह एक पुनरावर्ती तर्क है।
मूइंग डक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.