StackOverflowError से पुनर्प्राप्त करना क्यों संभव है?


100

मुझे आश्चर्य है कि StackOverflowErrorजावा में होने के बाद भी निष्पादन जारी रखना कैसे संभव है ।

मुझे पता है कि StackOverflowErrorक्लास एरर का एक सबस्क्रिप्शन है। वर्ग त्रुटि को "थ्रोबल के एक उपवर्ग के रूप में समझा जाता है जो गंभीर समस्याओं को इंगित करता है कि एक उचित अनुप्रयोग को पकड़ने की कोशिश नहीं करनी चाहिए।"

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

public class Test
{
    public static void main(String[] args)
    {
        try {
            foo();
        } catch (StackOverflowError e) {
            bar();
        }
        System.out.println("normal termination");
    }

    private static void foo() {
        System.out.println("foo");
        foo();
    }

    private static void bar() {
        System.out.println("bar");
    }
}

यह कैसे हो सकता है? मुझे लगता है कि जब तक StackOverflowError को फेंक दिया जाता है, तब तक स्टैक इतना भरा होना चाहिए कि किसी भी फ़ंक्शन को कॉल करने के लिए कोई जगह न हो। क्या त्रुटि हैंडलिंग ब्लॉक एक अलग स्टैक में चल रहा है, या यहाँ क्या चल रहा है?



57
मैं हर समय StackOverflow पर त्रुटी करता हूँ। हालांकि मुझे वापस आने से नहीं रोकता है।

10
यो डॉग ... मैंने सुना है आपको स्टैक ओवरफ्लो पसंद आया है इसलिए हमने आपके स्टैकओवरफ्लो.कॉम में स्टैक ओवरफ्लो डाला!
पियरे हेनरी

क्योंकि आधुनिक आर्किटेक्चर फ़्रेम पॉइंटर्स का उपयोग करने के लिए अनिच्छुक ढेर, यहां तक ​​कि आंशिक वाले को भी सुविधाजनक बनाते हैं। जब तक कोड + संदर्भ ऐसा न हो कि उसे गतिशील रूप से स्टैक से आवंटित न किया जाए, तब तक कोई समस्या नहीं होनी चाहिए।
RBarryYoung

जवाबों:


119

जब स्टैक ओवरफ्लो होता है और StackOverflowErrorफेंक दिया जाता है, तो सामान्य अपवाद हैंडलिंग स्टैक को खोल देता है। स्टैक को बंद करने का मतलब है:

  • वर्तमान में सक्रिय फ़ंक्शन के निष्पादन को निरस्त करें
  • इसके स्टैक फ्रेम को हटाएं, कॉलिंग फ़ंक्शन के साथ आगे बढ़ें
  • कॉल करने वाले का निष्पादन रद्द करें
  • इसके स्टैक फ्रेम को हटाएं, कॉलिंग फ़ंक्शन के साथ आगे बढ़ें
  • और इसी तरह...

... जब तक अपवाद नहीं पकड़ा जाता। यह सामान्य (वास्तव में, आवश्यक) और स्वतंत्र है कि किस अपवाद को फेंका गया है और क्यों। चूंकि आप पहली कॉल के बाहर अपवाद को पकड़ते हैं, स्टैक को भरने वाले foo()हज़ारों fooस्टैक फ्रेम सभी को खोल नहीं पाए हैं और अधिकांश स्टैक फिर से उपयोग करने के लिए स्वतंत्र है।


1
@fge संपादित करने के लिए स्वतंत्र महसूस करें, मैंने एक पैराग्राफ ब्रेक पर विचार किया लेकिन ऐसा स्थान नहीं मिला जहां यह अच्छा लगे।

1
आप बुलेट पॉइंट का उपयोग कर सकते हैं ... मैं अन्य लोगों के संपादन पद के लिए अनिच्छुक हूं;)
मर्ग

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

2
@delnan, मुझे लगता है कि यह उत्तर भी अधूरा है कि यह विस्तार से जाने बिना कि यह एक बुरा विचार क्यों है। स्पष्ट रूप से फेंके गए अपवाद का अंतर यह है कि Errorअपवाद सुरक्षित कोड लिखते समय भी प्रत्याशित नहीं किया जा सकता है।
साइमन रिक्टर

1
@SimonRichter नहीं, सवाल बहुत विशिष्ट है। यह एस से निपटने के बारे में नहीं हैError । ओपी केवल के बारे में पूछ रहा है StackOverflowError, और यह इस त्रुटि से निपटने की एक विशिष्ट बात पूछ रहा है : जब यह त्रुटि पकड़ी जाती है तो एक विधि कैसे विफल नहीं हो सकती।
बकुरीउ

23

जब StackOverflowError को फेंक दिया जाता है, तो स्टैक भर जाता है। हालांकि, जब यह पकड़ा जाता है , fooतो उन सभी कॉल को स्टैक से पॉप किया गया है। barसामान्य रूप से चल सकता है क्योंकि स्टैक अब foos के साथ बह नहीं रहा है । (ध्यान दें कि मुझे नहीं लगता कि JLS गारंटी देता है कि आप इस तरह से स्टैक ओवरफ्लो से उबर सकते हैं।)


12

जब StackOverFlow होता है, तो JVM स्टैक को मुक्त करते हुए पकड़ में आ जाएगा।

आप उदाहरण में, यह सभी स्टैक्ड फू के रैड मिलते हैं।


8

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


1
बस सावधान रहें यदि आप ऐसा करते हैं कि आपके अपवाद हैंडलर को उपलब्ध होने की तुलना में अधिक स्टैक स्थान की आवश्यकता नहीं है!
विंस

2

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

हालांकि, यह कहने के लिए बिल्कुल समान नहीं है कि यह सामान्य रूप से, एक से उबरने के लिए संभव है StackOverflowError

एक StackOverflowErrorIS-A VirtualMachineError, जो IS-AN है Error। जैसा कि आप बताते हैं, जावा एक के लिए कुछ अस्पष्ट सलाह देता है Error:

गंभीर समस्याओं को इंगित करता है कि एक उचित अनुप्रयोग को पकड़ने की कोशिश नहीं करनी चाहिए

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

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

...

  • StackOverflowError: जावा वर्चुअल मशीन कार्यान्वयन एक थ्रेड के लिए स्टैक स्पेस से बाहर चला गया है, आमतौर पर क्योंकि थ्रेड निष्पादन प्रोग्राम में एक गलती के परिणामस्वरूप पुनरावर्ती इनवॉइस की अनबाउंड संख्या कर रहा है।

महत्वपूर्ण समस्या यह है कि आप "भविष्यवाणी नहीं कर सकते" कहाँ या कब StackOverflowErrorफेंके जाएंगे। हैं कोई गारंटी जहां यह फेंक दिया नहीं किया जाएगा के बारे में। आप इस पर भरोसा नहीं कर सकते हैं कि उदाहरण के लिए, एक विधि में प्रवेश किया जा रहा है । इसे एक विधि के भीतर एक बिंदु पर फेंका जा सकता है ।

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

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