क्यों सी # 1 आकार में स्टैक आकार है?


102

आज के पीसी में बड़ी मात्रा में भौतिक रैम हैं लेकिन फिर भी, C # का स्टैक आकार 32-बिट प्रक्रियाओं के लिए केवल 1 एमबी और 64-बिट प्रक्रियाओं के लिए 4 एमबी ( सी # में स्टैक क्षमता ) है।

सीएलआर में स्टैक का आकार अभी भी इतना सीमित क्यों है?

और यह वास्तव में 1 एमबी (4 एमबी) (और 2 एमबी या 512 केबी) क्यों नहीं है? इन राशियों का उपयोग करने का निर्णय क्यों लिया गया?

मैं उस फैसले के पीछे की सोच और कारणों में दिलचस्पी रखता हूं ।


6
64bit प्रक्रियाओं के लिए डिफ़ॉल्ट स्टैक का आकार 4MB है, यह 32bit प्रक्रियाओं के लिए 1MB है। आप अपने PE शीर्ष लेख में मान बदलकर मुख्य-सूत्र स्टैक आकार को संशोधित कर सकते हैं । आप निर्माता के सही अधिभार का उपयोग करके स्टैक आकार भी निर्दिष्ट कर सकते हैं Thread। लेकिन, यह सवाल है, तुम एक बड़ा ढेर की आवश्यकता क्यों है?
युवल इत्जाचोव

2
धन्यवाद, संपादित :) सवाल यह नहीं है कि बड़े स्टैक आकार का उपयोग कैसे किया जाए, लेकिन स्टैक का आकार 1 एमबी (4 एमबी) क्यों होना तय है
निकोले कोस्तोव

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

2
@LucasTrzesniewski इतना ही नहीं, यह स्मृति में संक्रामक होना चाहिए । स्टैक के बड़े आकार पर ध्यान दें, कम प्रक्रिया आपकी प्रक्रिया अपने वर्चुअल एड्रेस स्पेस में बना सकती है।
युवल इत्जाचोव

"बिल्कुल" 1 एमबी के बारे में निश्चित नहीं है: मेरे विंडोज 8.1 पर, एक .NET कोर 3.1 कंसोल एप्लिकेशन में 1572864डिफ़ॉल्ट स्टैक आकार है (GetCurrentThreadStackLimits Win32 API का उपयोग करके पुनर्प्राप्त)। मैं StackOverflowException के बिना stackallocलगभग 1500000बाइट्स करने में सक्षम हूं ।
जॉर्ज चाकीजेज़

जवाबों:


210

यहां छवि विवरण दर्ज करें

आप उस आदमी को देख रहे हैं जिसने उस विकल्प को बनाया है। डेविड कटलर और उनकी टीम ने एक मेगाबाइट को डिफ़ॉल्ट स्टैक आकार के रूप में चुना। .NET या C # के साथ कुछ भी नहीं करना है, जब वे Windows NT बनाया गया था, तो इसे बंद कर दिया गया था। एक मेगाबाइट वह होता है जो किसी प्रोग्राम या CreateThread () winapi कॉल के EXE हेडर को स्पष्ट रूप से स्टैक आकार निर्दिष्ट नहीं करता है। जो सामान्य तरीका है, लगभग किसी भी प्रोग्रामर ने आकार लेने के लिए इसे ओएस छोड़ दिया।

यह पसंद शायद विंडोज़ एनटी डिज़ाइन को प्री-डेट करती है, इतिहास इस तरह से बहुत अधिक अजीब है। अच्छा होगा अगर कटलर इसके बारे में एक किताब लिखेंगे, लेकिन वह कभी लेखक नहीं रहे। वह कंप्यूटर के काम करने के तरीके पर असाधारण रूप से प्रभावशाली रहा है। उनका पहला OS डिज़ाइन RSX-11M, DEC कंप्यूटर (डिजिटल उपकरण निगम) के लिए 16-बिट ऑपरेटिंग सिस्टम था। इसने 8-बिट माइक्रोप्रोसेसर के लिए गैरी किल्डल के CP / M, पहले सभ्य OS को बहुत प्रभावित किया। जिसने MS-DOS को भारी प्रभावित किया।

उनका अगला डिज़ाइन VMS था, जो वर्चुअल मेमोरी सपोर्ट के साथ 32-बिट प्रोसेसर के लिए एक ऑपरेटिंग सिस्टम था। बहुत सफल। सस्ते पीसी हार्डवेयर के साथ प्रतिस्पर्धा करने में सक्षम नहीं होने के कारण कंपनी द्वारा डिस्क्टेटिंग शुरू करने के बाद उनका अगला एक DEC रद्द कर दिया गया। Microsoft को, उन्होंने उसे एक ऐसा प्रस्ताव दिया जिसे वह अस्वीकार नहीं कर सकता था। उनके कई सहकर्मी भी इसमें शामिल हुए। उन्होंने VMS v2 पर काम किया, जिसे विंडोज़ एनटी के नाम से जाना जाता है। डीईसी इसके बारे में परेशान हो गया, इसे निपटाने के लिए पैसे ने हाथ बदल दिया। क्या VMS ने पहले से ही एक मेगाबाइट को चुना है जो मुझे नहीं पता, मैं केवल RSX-11 को अच्छी तरह से जानता हूं। यह संभावना नहीं है।

पर्याप्त इतिहास। एक मेगाबाइट एक बहुत है , एक असली धागा शायद ही कभी मुट्ठी भर किलोबाइट से अधिक खपत करता है। तो एक मेगाबाइट वास्तव में बेकार है। हालाँकि यह एक तरह की बर्बादी है जो आप एक डिमांड-पास्ड वर्चुअल मेमोरी ऑपरेटिंग सिस्टम पर खर्च कर सकते हैं, वह मेगाबाइट सिर्फ वर्चुअल मेमोरी है । बस प्रोसेसर के लिए नंबर, हर 4096 बाइट्स के लिए एक-एक। आप वास्तव में भौतिक मेमोरी, मशीन में रैम का उपयोग कभी नहीं करते हैं, जब तक आप वास्तव में इसे संबोधित नहीं करते हैं।

यह .NET प्रोग्राम में अतिरिक्त है क्योंकि मूल कार्यक्रमों को समायोजित करने के लिए मूल रूप से एक मेगाबाइट का आकार चुना गया था। जो स्टैक पर बड़े स्टैक फ्रेम और स्ट्रिंग्स और बफ़र्स (सरणियाँ) बनाने के लिए करते हैं। मैलवेयर हमला वेक्टर होने के लिए बदनाम, एक बफर अतिप्रवाह डेटा के साथ कार्यक्रम में हेरफेर कर सकता है। नहीं। जिस तरह से .NET प्रोग्राम काम करते हैं, स्ट्रिंग्स और सरणियों को जीसी हीप पर आवंटित किया जाता है और इंडेक्सिंग की जांच की जाती है। सी # के साथ स्टैक पर जगह आवंटित करने का एकमात्र तरीका असुरक्षित स्टैकॉलॉक कीवर्ड के साथ है।

.NET में स्टैक का एकमात्र गैर-तुच्छ उपयोग जटर द्वारा किया जाता है। यह एमएसआईएल को मशीन कोड के लिए समय-समय पर संकलन के लिए अपने धागे के ढेर का उपयोग करता है। मैंने कभी नहीं देखा या जाँच नहीं किया है कि इसे कितनी जगह की आवश्यकता है, यह कोड की प्रकृति पर निर्भर करता है और ऑप्टिमाइज़र सक्षम है या नहीं, लेकिन दसियों किलोबाइट की एक जोड़ी एक मोटा अनुमान है। जो अन्यथा इस वेबसाइट को अपना नाम कैसे मिला, .NET प्रोग्राम में स्टैक ओवरफ्लो काफी घातक है। अभी भी पर्याप्त स्थान नहीं बचा है (3 किलोबाइट से कम) जो अभी भी अपवाद को पकड़ने की कोशिश करने वाले किसी भी कोड को मज़बूती से JIT कर रहे हैं। Kaboom to Desktop ही एकमात्र विकल्प है।

पिछले नहीं बल्कि कम से कम, एक .NET प्रोग्राम स्टैक के साथ बहुत अनुत्पादक करता है। सीएलआर एक धागे के ढेर को प्रतिबद्ध करेगा । यह एक महंगा शब्द है, जिसका अर्थ है कि यह केवल स्टैक के आकार को आरक्षित नहीं करता है, यह यह भी सुनिश्चित करता है कि ऑपरेटिंग सिस्टम की पेजिंग फ़ाइल में स्थान आरक्षित है ताकि आवश्यक होने पर स्टैक को हमेशा स्वैप किया जा सके। करने के लिए असफल एक घातक त्रुटि है और बिना शर्त के एक कार्यक्रम को समाप्त करता है। यह केवल बहुत कम रैम के साथ मशीन पर होता है जो पूरी तरह से बहुत सारी प्रक्रियाओं को चलाता है, इस तरह की मशीन मरने से पहले प्रोग्रामों में बदल जाएगी। 15+ साल पहले एक संभावित समस्या, आज नहीं। प्रोग्रामर जो एफ 1 रेस-कार की तरह कार्य करने के लिए अपने प्रोग्राम को ट्यून करते हैं, <disableCommitThreadStack>उनकी .config फ़ाइल में तत्व का उपयोग करते हैं ।

Fwiw, Cutler ने ऑपरेटिंग सिस्टम डिजाइन करना बंद नहीं किया। वह तस्वीर तब बनी थी जब उन्होंने अज़ूर पर काम किया था।


अद्यतन, मैंने देखा कि .NET अब स्टैक नहीं करता है। निश्चित रूप से नहीं कि यह कब या क्यों हुआ, यह बहुत लंबा हो गया है जब से मैंने जाँच की है। मुझे लगता है कि यह डिज़ाइन परिवर्तन .NET 4.5 के आसपास कहीं हुआ है। बहुत समझदार बदलाव।


3
आपकी टिप्पणी के लिए wrt The only way to allocate space on the stack with C# is with the unsafe stackalloc keyword.- स्थानीय चर उदाहरण हैं जो intएक विधि के अंदर घोषित किया जाता है जो स्टैक पर संग्रहीत नहीं है? मुझे लगता है वे हैं।
RBT

2
ठीक। अब मुझे यह समझ में आया कि एक स्टैक-फ्रेम किसी फ़ंक्शन के स्थानीय चर के लिए भंडारण का एकमात्र विकल्प नहीं है। यह एक स्टैक फ्रेम पर संग्रहीत किया जा सकता है, जैसा कि आपके बुलेट बिंदुओं में से एक में सुझाया गया है। बहुत ज्ञानवर्धक हंस। मैं इस तरह के व्यावहारिक पोस्ट लिखने के लिए आपको बहुत धन्यवाद नहीं कह सकता। ईमानदारी से स्टैक करना अनावश्यक रूप से जटिलता से बचने के लिए सामान्य रूप से प्रोग्रामिंग के लिए इतना बड़ा अमूर्त है।
RBT

बहुत विस्तृत वर्णन @ हं। मैं सोच रहा था कि maxStackSizeएक सूत्र के लिए न्यूनतम संभव मूल्य क्या है ? मैं इसे [MSDN] ( msdn.microsoft.com/en-us/library/5cykbwz4(v=vs.110).aspx ) पर नहीं ढूंढ सका । आपकी टिप्पणियों के आधार पर ऐसा लगता है कि स्टैक का उपयोग पूर्ण न्यूनतम है और मैं अधिकतम संभव थ्रेड्स को समायोजित करने के लिए सबसे छोटे मूल्य का उपयोग कर सकता हूं। धन्यवाद।
एमकेआर

1
@KFL: आप अपने प्रश्न का उत्तर आसानी से आजमा कर देख सकते हैं!
एरिक लिपर्ट

1
यदि डिफ़ॉल्ट व्यवहार अब स्टैक करने के लिए नहीं है, तो इस मार्कडाउन फ़ाइल को github.com/dotnet/docs/blob/master/docs/framework/…
John Stewien

5

डिफ़ॉल्ट आरक्षित स्टैक का आकार लिंकर द्वारा निर्दिष्ट किया जाता है और इसे डेवलपर्स द्वारा लिंक समय पर पीई मूल्य को बदलकर या व्यक्तिगत थ्रेड के लिए dwStackSizeपैरामीटर निर्दिष्ट करके पैरामीटर द्वारा ओवरराइड किया जा सकता हैCreateThread WinAPI फ़ंक्शन के ।

यदि आप डिफ़ॉल्ट स्टैक आकार से बड़ा या इसके बराबर प्रारंभिक स्टैक आकार के साथ एक थ्रेड बनाते हैं तो यह निकटतम 1 एमबी के कई तक हो जाता है।

मान 32-बिट प्रक्रियाओं के लिए 1 एमबी और 64-बिट के लिए 4 एमबी के बराबर क्यों है? मुझे लगता है कि आपको डेवलपर्स से पूछना चाहिए, जिन्होंने विंडोज डिज़ाइन किया है, या तब तक प्रतीक्षा करें जब तक कि उनमें से कोई आपके प्रश्न का उत्तर न दे।

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

लेकिन इस समय मैं कुछ संभावित कारणों की व्याख्या करने की कोशिश करूँगा कि Microsoft ने MSDN, Mark's और Raymond के ब्लॉगों का उपयोग करके इन मूल्यों को क्यों चुना है।

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

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

आजकल इन मूल्यों का उपयोग ज्यादातर पिछड़े संगतता के लिए किया जाता है, क्योंकि जो संरचनाएं WinAPI फ़ंक्शन के मापदंडों के रूप में पारित की जाती हैं, वे अभी भी स्टैक पर आवंटित की जाती हैं। लेकिन यदि आप स्टैक आवंटन का उपयोग नहीं कर रहे हैं, तो थ्रेड का स्टैक उपयोग डिफ़ॉल्ट 1 एमबी से काफी कम होगा और यह हंस पैसिव के रूप में उल्लिखित है। और इसे रोकने के लिए OS केवल स्टैक के पहले पृष्ठ (4 KB) को लागू करता है, अगर अन्य एप्लिकेशन के पीई हेडर में निर्दिष्ट नहीं है। अन्य पृष्ठ मांग पर आवंटित किए गए हैं।

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

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

सूत्रों का कहना है:

  1. धागा ढेर का आकार (Microsoft डॉक्स)
  2. विंडोज की सीमाएं धक्का: प्रक्रियाएं और सूत्र (मार्क रोसिनोविच)
  3. डिफ़ॉल्ट रूप से, मूल IIS प्रक्रिया में बनाए गए थ्रेड का अधिकतम स्टैक आकार 256 KB (KB932909) है

यदि मुझे एक बड़ा स्टैक आकार चाहिए तो मैं इसे सेट कर सकता हूं ( atalasoft.com/cs/blogs/rickm/archive/2008/04/22/… )। मैं उस निर्णय के पीछे की बातों और कारणों को जानना चाहता हूं।
निकोले कोस्तोव

2
ठीक है। अब मैं आपको समझाता हूं :) डिफ़ॉल्ट स्टैक का आकार इष्टतम होना चाहिए (@Lucas Trzesniewski टिप्पणी देखें) और आवंटन ग्रैन्युलैरिटी के निकटतम कई पर गोल होना चाहिए। यदि निर्दिष्ट स्टैक का आकार डिफ़ॉल्ट स्टैक आकार से बड़ा है, तो यह निकटतम 1MB के कई तक हो जाता है। इसलिए Microsoft ने सभी उपयोगकर्ता मोड एप्लिकेशन के लिए इस आकार को डिफ़ॉल्ट स्टैक आकार के रूप में चुना। और कोई अन्य कारण नहीं हैं।
योह डेडफॉल

कोई स्रोत? कोई दस्तावेज? :)
निकोले कोस्तोव

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