C # स्टैक ओवरफ़्लो अपवाद को पकड़ें


115

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

क्या स्टैक ओवरफ्लो अपवाद एक विशेष तरीके से व्यवहार करता है? क्या मैं अपवाद को ठीक से पकड़ / संभाल सकता हूँ?

यकीन नहीं तो प्रासंगिक, लेकिन अतिरिक्त जानकारी:

  • मुख्य धागे में अपवाद नहीं फेंका गया है

  • ऑब्जेक्ट जहां कोड अपवाद को फेंक रहा है, उसे मैन्युअल रूप से असेंबली द्वारा लोड किया जाता है। LadFrom (...)। CreateInstance (...)


3
@ रिचर्ड, निश्चित रूप से मैं बग को ठीक करता हूं क्योंकि यह एक बग था। हालाँकि यह मुद्दा एक अलग तरीके से प्रकट हो सकता है और मैं इसे संभालना चाहता हूँ
टोटो

7
सहमत, एक स्टैक ओवरफ्लो एक गंभीर त्रुटि है जिसे पकड़ा नहीं जा सकता क्योंकि इसे पकड़ा नहीं जाना चाहिए । इसके बजाय टूटे हुए कोड को ठीक करें।
इयान केम्प

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

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

जवाबों:


109

2.0 के साथ शुरू एक StackOverflow अपवाद केवल निम्नलिखित परिस्थितियों में पकड़ा जा सकता है।

  1. CLR एक होस्टेड वातावरण में चलाया जा रहा है * जहाँ होस्ट विशेष रूप से StackOverflow अपवादों को संभालने की अनुमति देता है
  2. स्टैकओवरफ़्लो अपवाद उपयोगकर्ता कोड द्वारा फेंका गया है और वास्तविक स्टैक ओवरफ़्लो स्थिति ( संदर्भ ) के कारण नहीं

* "होस्टेड वातावरण" के रूप में "मेरा कोड सीएलआर होस्ट करता है और मैं सीएलआर के विकल्प कॉन्फ़िगर करता हूं" और "मेरा कोड" मेरे होस्टिंग पर नहीं चलता है "


27
यदि यह किसी भी संबंधित scebario में नहीं पकड़ा जा सकता है, तो StackoverflowException ऑब्जेक्ट मौजूद क्यों है?
मनु

9
@ मनु कम से कम एक दो कारणों से। 1) क्या यह पकड़ा जा सकता है, 1.1 में तरह का, और इसलिए इसका एक उद्देश्य था। 2) यह अभी भी पकड़ा जा सकता है यदि आप सीएलआर की मेजबानी कर रहे हैं, तो यह अभी भी एक वैध अपवाद प्रकार है
जेरेडपर

3
यदि इसे पकड़ा नहीं जा सकता ... तो विंडोज़ घटना यह क्यों नहीं बताती है कि क्या हुआ, डिफ़ॉल्ट रूप से पूर्ण स्टैक ट्रेस शामिल हैं?

10
कैसे एक होस्ट वातावरण में StackOverflowException को नियंत्रित करने की अनुमति देने के बारे में जाना जाता है? कारण मैं पूछ रहा हूं क्योंकि मैं एक होस्ट किया गया वातावरण चलाता हूं, और मुझे यह सटीक समस्या हो रही है, जहां यह पूरे ऐप पूल को नष्ट कर देता है। मैं बहुत कुछ करना चाहूंगा, लेकिन यह थ्रेड को निरस्त कर देता है, जहां यह शीर्ष तक वापस पहुंच सकता है, और मैं तब त्रुटि को लॉग इन कर सकता हूं और सभी एपल के थ्रेड्स को मारे बिना जारी रख सकता हूं।
ब्रेन २००

Starting with 2.0 ..., मैं उत्सुक हूं, उन्हें एसओ को पकड़ने से क्या रोक रहा है और यह कैसे संभव था 1.1(आपने अपनी टिप्पणी में इसका उल्लेख किया है)?
एम। केज़म अख़गरी

47

सही तरीका ओवरफ्लो को ठीक करना है, लेकिन ...।

आप अपने आप को एक बड़ा ढेर दे सकते हैं: -

using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();

फ़्रेम सीमा तक पहुंचने पर आपके द्वारा उपयोग किए गए फ़्रेम को गिनने और अपना अपवाद फेंकने के लिए आप System.Diagnostics.StackTrace FrameCount प्रॉपर्टी का उपयोग कर सकते हैं।

या, आप शेष के आकार की गणना कर सकते हैं और अपने स्वयं के अपवाद को फेंक सकते हैं जब यह एक सीमा से नीचे आता है: -

class Program
{
    static int n;
    static int topOfStack;
    const int stackSize = 1000000; // Default?

    // The func is 76 bytes, but we need space to unwind the exception.
    const int spaceRequired = 18*1024; 

    unsafe static void Main(string[] args)
    {
        int var;
        topOfStack = (int)&var;

        n=0;
        recurse();
    }

    unsafe static void recurse()
    {
        int remaining;
        remaining = stackSize - (topOfStack - (int)&remaining);
        if (remaining < spaceRequired)
            throw new Exception("Cheese");
        n++;
        recurse();
    }
}

बस पनीर पकड़ लो। ;)


47
Cheeseविशिष्ट से बहुत दूर है। मैं throw new CheeseException("Gouda");
सी। ईवेनहिस के

13
@ C.Evenhuis Whilst इसमें कोई शक नहीं है कि Gouda एक असाधारण पनीर है यह एक RollingCheeseException ("डबल ग्लूसेस्टर") होना चाहिए वास्तव में पनीर देखें-.co.uking.co.uk

3
lol, 1) फिक्सिंग संभव नहीं है क्योंकि इसे पकड़े बिना आप अक्सर यह नहीं जानते कि यह 2 कहाँ होता है) Stacksize को अंतहीन पुनरावृत्ति के साथ बेकार करना है andm 3) सही स्थान पर Stack की जाँच करना पहले की तरह है
Firo

2
लेकिन मैं लैक्टोज असहिष्णु हूँ
redoc

39

StackOverflowException s पर MSDN पृष्ठ से :

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

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


23

जैसा कि कई उपयोगकर्ता पहले ही कह चुके हैं, आप अपवाद नहीं पकड़ सकते। हालाँकि, यदि आप यह पता लगाने के लिए संघर्ष कर रहे हैं कि यह कहाँ हो रहा है, तो आप फेंके जाने पर दृश्य स्टूडियो को कॉन्फ़िगर करना चाह सकते हैं।

ऐसा करने के लिए, आपको 'डीबग' मेनू से अपवाद सेटिंग्स खोलने की आवश्यकता है। विज़ुअल स्टूडियो के पुराने संस्करणों में, यह 'डीबग' - 'अपवाद' पर है; नए संस्करणों में, यह 'डीबग' - 'विंडोज' - 'अपवाद सेटिंग्स' पर है।

एक बार जब आपके पास सेटिंग्स खुल जाती है, तो 'सामान्य भाषा रनटाइम अपवाद' का विस्तार करें, 'सिस्टम' का विस्तार करें, नीचे स्क्रॉल करें और 'System.StackOverflowException' जांचें। फिर आप कॉल स्टैक को देख सकते हैं और कॉल के दोहराए जाने वाले पैटर्न की तलाश कर सकते हैं। आपको यह विचार करना चाहिए कि स्टैक ओवरफ़्लो का कारण बनने वाले कोड को ठीक करने के लिए कहाँ देखना है।


1
डिबग कहां है - वीएस 2015 में अपवाद?
FrenkyB

1
डीबग - विंडोज - अपवाद सेटिंग्स
साइमन

15

जैसा कि कई बार ऊपर उल्लेख किया गया है, सिस्टम द्वारा भ्रष्ट प्रक्रिया के कारण उठाए गए StackOverflowException को पकड़ना संभव नहीं है। लेकिन एक घटना के रूप में अपवाद को नोटिस करने का एक तरीका है:

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

.NET फ्रेमवर्क संस्करण 4 से शुरू होकर, यह घटना अपवादों के लिए नहीं उठती है, जो प्रक्रिया की स्थिति को दूषित करती है, जैसे कि स्टैक ओवरफ्लो या एक्सेस उल्लंघन, जब तक कि ईवेंट हैंडलर सुरक्षा-महत्वपूर्ण नहीं होता है और उसके पास हैंडलेप्रोसेसक्रॉप्डस्ट्रीमस्टैडऐसेप्टिव विशेषता है।

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

.NET फ्रेमवर्क संस्करणों 1.0 और 1.1 में, एक अखंड अपवाद जो मुख्य एप्लिकेशन थ्रेड के अलावा थ्रेड में होता है, रनटाइम द्वारा पकड़ा जाता है और इसलिए एप्लिकेशन को समाप्त करने का कारण नहीं बनता है। इस प्रकार, यह संभव है कि अनहेल्डेडसेप्शन ईवेंट को एप्लिकेशन को समाप्त किए बिना उठाया जाए। .NET फ्रेमवर्क संस्करण 2.0 से शुरू होकर, बच्चे के थ्रेड्स में बिना किसी अपवाद के इस बैकस्टॉप को हटा दिया गया था, क्योंकि ऐसी मूक विफलताओं के संचयी प्रभाव में प्रदर्शन में गिरावट, दूषित डेटा और लॉकअप शामिल थे, जिनमें से सभी को डीबग करना मुश्किल था। अधिक जानकारी के लिए, उन मामलों की सूची जिसमें रनटाइम समाप्त नहीं होता है, में प्रबंधित थ्रेड्स में अपवाद देखें।


6

हां CLR 2.0 स्टैक ओवरफ्लो को एक गैर-वसूली योग्य स्थिति माना जाता है। इसलिए रनटाइम अभी भी प्रक्रिया को बंद कर देता है।

जानकारी के लिए कृपया दस्तावेज देखें http://msdn.microsoft.com/en-us/library/system.stackoverflowex.nx


सीएलआर 2.0 StackOverflowExceptionसे डिफ़ॉल्ट रूप से प्रक्रिया को समाप्त करता है।
ब्रायन रासमुसेन

नहीं, आप OOM को पकड़ सकते हैं और कुछ मामलों में ऐसा करने का कोई मतलब हो सकता है। मुझे पता नहीं है कि थ्रेड गायब होने से आपका क्या मतलब है। यदि किसी थ्रेड में एक अनहेल्दी अपवाद है, तो CLR प्रक्रिया को समाप्त कर देगा। यदि आपका धागा अपनी विधि पूरी करता है तो इसे साफ किया जाएगा।
ब्रायन रासमुसेन

5

आप नहीं कर सकते। सीएलआर आपको ऐसा नहीं करने देगा। स्टैक ओवरफ्लो एक घातक त्रुटि है और इससे पुनर्प्राप्त नहीं किया जा सकता है।


तो आप इस अपवाद के लिए एक यूनिट टेस्ट को कैसे असफल कर देते हैं अगर कैटलेबल होने के बजाय यह यूनिट टेस्ट रनर को क्रैश कर देता है?
BrainSlugs83

1
@ BrainSlugs83। तुम नहीं, क्योंकि यह एक मूर्खतापूर्ण विचार है। यदि आपका कोड StackOverflowException के साथ वैसे भी विफल रहता है तो आप परीक्षण क्यों कर रहे हैं? यदि CLR बदल जाता है तो क्या होता है ताकि यह एक गहरे ढेर को संभाल सके? यदि आप अपनी यूनिट के परीक्षण किए गए फ़ंक्शन को कहीं और कॉल करते हैं तो पहले से ही एक नेस्टेड स्टैक है? ऐसा लगता है कि कुछ परीक्षण करने में सक्षम नहीं है। यदि आप इसे मैन्युअल रूप से फेंकने की कोशिश कर रहे हैं, तो कार्य के लिए बेहतर अपवाद चुनें।
मैथ्यू शारले

5

आप ज्यादातर पोस्ट नहीं समझा सकते हैं, मुझे एक और क्षेत्र जोड़ने दें:

कई वेबसाइटों पर आप लोगों को यह कहते हुए पाएंगे कि इससे बचने का तरीका एक अलग AppDomain का उपयोग कर रहा है ताकि ऐसा होने पर डोमेन लोड हो जाए। यह बिल्कुल गलत है (जब तक आप अपने सीएलआर की मेजबानी नहीं करते हैं) सीएलआर के डिफ़ॉल्ट व्यवहार के रूप में आपके डिफ़ॉल्ट एपडोमैन को नीचे लाते हुए एक किलप्रोसेस घटना बढ़ेगी।


3

यह असंभव है, और एक अच्छे कारण के लिए (एक के लिए, उन सभी कैच के बारे में सोचें (अपवाद) {} के आसपास)।

यदि आप स्टैक ओवरफ्लो के बाद निष्पादन जारी रखना चाहते हैं, तो एक अलग AppDomain में खतरनाक कोड चलाएं। मूल डोमेन को प्रभावित किए बिना ओवरफ्लो पर वर्तमान AppDomain को समाप्त करने के लिए CLR नीतियां निर्धारित की जा सकती हैं।


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

4
कुछ बिंदु पर बयान अच्छी तरह से नहीं सोचा गया है। यदि आप स्टैकओवरफ़्लो को नहीं पकड़ सकते हैं तो आप शायद कभी नहीं जान पाएंगे कि यह उत्पादन वातावरण में क्या हुआ है।
ऑफ्लर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.