सवाल StackOverflowException फेंक दिया जाता है जब .NET इतना खराब व्यवहार करता है?


मुझे पता है कि .NET में StackOverflowExceptions को पकड़ा नहीं जा सकता है, अपनी प्रक्रिया को कम कर सकते हैं, और कोई स्टैक ट्रेस नहीं है। यह आधिकारिक तौर पर दस्तावेज है एमएसडीएन पर। हालांकि, मैं सोच रहा हूं कि व्यवहार के पीछे तकनीकी (या अन्य) कारण क्या हैं। सभी एमएसडीएन कहते हैं:

.NET Framework के पूर्व संस्करणों में, आपका एप्लिकेशन पकड़ सकता है   एक StackOverflowException ऑब्जेक्ट (उदाहरण के लिए, से पुनर्प्राप्त करने के लिए   असंबद्ध रिकर्सन)। हालांकि, यह अभ्यास वर्तमान में निराश है   क्योंकि विश्वसनीय रूप से पकड़ने के लिए महत्वपूर्ण अतिरिक्त कोड की आवश्यकता होती है   ढेर ओवरफ्लो अपवाद और प्रोग्राम निष्पादन जारी रखें।

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


58
2018-03-17 21:14


मूल


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


जवाब:


एक थ्रेड का ढेर विंडोज द्वारा बनाया गया है। यह तथाकथित का उपयोग करता है गार्ड पेज एक ढेर अतिप्रवाह का पता लगाने में सक्षम होने के लिए। एक सुविधा जो आमतौर पर वर्णित उपयोगकर्ता मोड कोड के लिए उपलब्ध है यह एमएसडीएन पुस्तकालय लेख। मूल विचार यह है कि स्टैक के अंतिम दो पृष्ठ (2 x 4096 = 8192 बाइट्स) हैं सुरक्षित और उनके लिए कोई भी प्रोसेसर एक्सेस पेज पेज गलती को ट्रिगर करता है जो एक एसईएच अपवाद, STATUS_GUARD_PAGE_VIOLATION में बदल जाता है।

थ्रेड स्टैक से संबंधित उन पृष्ठों के मामले में कर्नेल द्वारा इसे अवरुद्ध किया जाता है। यह उन 2 पृष्ठों में से पहले की सुरक्षा विशेषताओं को बदलता है, इस प्रकार दुर्घटना से निपटने के लिए थ्रेड को कुछ आपातकालीन स्टैक स्पेस देता है, फिर STATUS_STACK_OVERFLOW अपवाद को फिर से उठाता है।

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

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

यदि किसी अन्य धागे पर किसी ईवेंट को बढ़ाने या Winapi में प्रतिबंध को हटाने में विचार करने पर कोई प्रयास किया गया था (गार्ड पृष्ठों की संख्या कॉन्फ़िगर करने योग्य नहीं है) तो यह या तो बहुत अच्छी तरह से रखा गया रहस्य है या बस उपयोगी नहीं माना गया था। मुझे बाद में संदेह है, इसे एक तथ्य के लिए नहीं जानते।


84
2018-03-17 23:38



इसके लिए +1 "संभावना है कि एक प्रोग्राम पूरी तरह से यादृच्छिक स्थान पर छोड़े गए थ्रेड के साथ सही तरीके से परिचालन जारी रख सकता है और बल्कि दूषित राज्य अकेले" असंभव "है। अगर लोग केवल यह प्राप्त करेंगे - ऐसी परिस्थितियों पर ध्यान दिए बिना ऐसी स्थिति का कारण बनता है। - Christian.K
यह वही जानकारी है जिसे मैं ढूंढ रहा था। कोई विचार है कि हम अपवाद के साथ कम से कम एक स्टैक ट्रेस क्यों नहीं प्राप्त कर सकते हैं? - ChaseMedallion
मैं इसे नहीं खरीदता ओपी एक उद्धरण के साथ शुरू होता है जो दर्शाता है कि यह संभव होता था, इसलिए असली सवाल बदल गया है। - Gabe
एचएमए, सीएलआर v1.x नीति सिर्फ थ्रेड को ऐपडोमेन के बिना मरने की अनुमति देती है। अनचाहे अपवाद कॉलबैक व्यापक रूप से तुच्छ था। माइक्रोसॉफ्ट में विंडोज समूह को प्रबंधित कोड से नफरत करने के लिए मिला जब उन्होंने लॉन्गहोर्न में इसका उपयोग करने की कोशिश की। - Hans Passant
इसके अलावा, यह पता लगाने के लिए एक दिलचस्प अभ्यास हो सकता है कि मोनो इसे कैसे संभालता है। - Eric Lloyd


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

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


16
2018-03-17 21:18



@pasty ढेर लपेटा नहीं है। थ्रेड बनने पर प्रबंधित स्टैक के लिए संग्रहण आवंटित और प्रतिबद्ध किया जाता है। रन-टाइम पर इसे विस्तारित करने का कोई विकल्प नहीं है। - Brian Rasmussen
क्यों न केवल मौजूदा धागे को नष्ट कर दें जो ढेर से बहती है? पूरी प्रक्रिया को क्यों मारने की जरूरत है? - Bob Albright
@BobAlbright क्योंकि ऐसा करने का मतलब यह होगा कि प्रक्रिया एक अनिर्धारित स्थिति में होगी। - Brian Rasmussen
जावा इसे संभालता है ... मुझे कारण नहीं दिख रहा है कि .NET ऐसा क्यों नहीं कर सकता है। मैं यह भी नहीं देखता कि यह अंतिम गैर-ओवरफ्लो स्टैक फ्रेम पर वापस क्यों नहीं जा सकता है और वहां से सामान्य रूप से (अपवाद के लिए) आगे बढ़ सकता है। - ChaseMedallion
@dvnrrs: यह मेरे प्रश्न का सार है। .NET ने एसओ को सावधानीपूर्वक संभालने का फैसला क्यों नहीं किया? - ChaseMedallion


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

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


7
2018-03-17 22:36