2009-11-07 11 views
47

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

उत्तर

78

यह कोई अपवाद नहीं है; यह एक त्रुटि है: java.lang.OutOfMemoryError

आप कर सकते हैं पकड़ के रूप में यह फेंकने योग्य से उतरता है यह:

try { 
    // create lots of objects here and stash them somewhere 
} catch (OutOfMemoryError E) { 
    // release some (all) of the above objects 
} 

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

+14

इसके अलावा, वहाँ की संभावना कोई आसान तरीका आप अगर यह से उबरने के लिए के लिए है आप इसे पकड़ते हैं। –

+0

@matt b - विशिष्ट मामले में जहां आप ** सक्षम हैं ** इसे पकड़ने के लिए आप संभावित रूप से अपनी मेमोरी खपत को नियंत्रित करने की कोशिश कर रहे हैं और इस प्रकार कुछ/सभी को रिलीज़ करने में सक्षम होंगे। लेकिन आम तौर पर बोलते हुए आप सही हैं। – ChssPly76

+0

@ ChssPly76 (और अन्य) - कृपया यह समझने के लिए मेरा जवाब पढ़ें कि ओओएमई को पकड़कर स्मृति खपत का प्रबंधन करने का प्रयास क्यों किया जाएगा ** बीएडी आईडीईए **। –

1

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

+1

आपकी योजना में इस संभावना से निपटने के लिए एक रणनीति शामिल करनी होगी कि आपका कार्यक्रम एक असंगत स्थिति में है; http://stackoverflow.com/questions/8728866/no-throw-virtualmachineerror- गारंटी – Raedwald

48

यह संभव है:

try { 
    // tragic logic created OOME, but we can blame it on lack of memory 
} catch(OutOfMemoryError e) { 
    // but what the hell will you do here :) 
} finally { 
    // get ready to be fired by your boss 
} 
+10

वहां * कम से कम एक उचित चीज है जो आप कर सकते हैं जो ओओएमई का कारण बनता है और पुनर्प्राप्त करने योग्य होता है: एक बहुत बड़ी छवि लोड हो रही है। कोशिश ब्लॉक में एकमात्र चीज ImageIO.read() पर एक कॉल है, और आप उपयोगकर्ता को एक संवाद दिखा रहे हैं कि कैच ब्लॉक में छवि बहुत बड़ी है। बस कह रहा है ... – uckelman

+1

@uckelman यह एक गलत दृष्टिकोण है, जब तक कि आपका ऐप एकल थ्रेड न हो। बात यह है कि भले ही आपकी छवि-लोडिंग-थ्रेड ओओएमई को पकड़ लेती है, लेकिन अन्य धागे इस बारे में नहीं जानते हैं और ओओएमई भी प्राप्त कर सकते हैं –

+4

@ सूरजचंद्रन: ओओएमई बहुत बड़ी छवि लोड करने का प्रयास करने के कारण होता है एक बहुत बड़ा 'बाइट []' या 'int []' आवंटित करें। आप उस से ओओएमई प्राप्त करते हैं क्योंकि आवंटन विफल रहता है, क्योंकि आप वास्तव में स्मृति से बाहर नहीं हैं --- इसलिए यह अन्य धागे पर कोई समस्या नहीं पैदा करेगा। एक दिलचस्प समाधान के लिए – uckelman

1

यह को पकड़ने के लिए किसी भी अपवाद संभव है। बस

try{ 
    // code which you think might throw exception 
}catch(java.lang.Throwable t){ 
    // you got the exception. Now what?? 
} 

आदर्श रूप में आप java.lang.Error अपवाद को पकड़ने के लिए नहीं जा सकते लिखें। ऐसे अपवादों को नहीं पकड़ना, और एप्लिकेशन को समाप्त होने देना सबसे अच्छा समाधान हो सकता है जब वे होते हैं। अगर आपको लगता है कि आप इस तरह की त्रुटि को बहुत अच्छी तरह से संभाल सकते हैं, तो आगे बढ़ें।

2

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

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

24

आप पकड़ कर सकते हैं और OutOfMemoryError (OOM) अपवाद हैं, से उबरने के लिए प्रयास लेकिन यह शायद एक बुरा विचार है ... खासकर यदि आपकी उद्देश्य आवेदन करने के लिए "जारी रखने के लिए" है।

इस के लिए कई कारणों से कर रहे हैं:

  1. के रूप में अन्य लोगों ने बताया है, वहाँ बेहतर तरीके स्पष्ट रूप से चीजों को मुक्त कराने से स्मृति संसाधनों का प्रबंधन करने कर रहे हैं; यानी ऑब्जेक्ट्स के लिए सॉफ्ट रेफरेंस और वीक रेफरेंस का उपयोग करना जो स्मृति कम होने पर मुक्त हो सकता है।

  2. यदि आप चीजों को मुक्त करने से पहले वास्तव में स्मृति से बाहर निकलने तक प्रतीक्षा करते हैं, तो आपके आवेदन को कचरा कलेक्टर चलाने में अधिक समय व्यतीत करने की संभावना है। आपके जेवीएम संस्करण और आपके जीसी ट्यूनिंग पैरामीटर के आधार पर, जेवीएम जीसी को अधिक से अधिक बार चला सकता है क्योंकि यह उस बिंदु तक पहुंचता है जिस पर ओओएम फेंक देगा। मंदी (उपयोगी काम करने वाले आवेदन के मामले में) महत्वपूर्ण हो सकता है। आप शायद इससे बचना चाहते हैं।

  3. यदि आपकी समस्या का मूल कारण स्मृति रिसाव है, तो संभावना है कि ओओएम से पकड़ने और पुनर्प्राप्त करने से लीक मेमोरी पुनः प्राप्त नहीं होगी। आप फिर से ओओएम के लिए फिर से चलते रहेंगे, और फिर, और कभी अंतराल को कम करने पर।

    • जहां और क्यों यह OOM हुआ,
    • वहाँ नहीं होगा:

तो मेरी सलाह एक OOM से जा रहा ... जब तक आप जानते हैं रखने का प्रयास नहीं किया जाता है कोई भी "संपार्श्विक क्षति", और

  • है कि आपकी वसूली जारी रखने के लिए पर्याप्त स्मृति जारी करेगी।
  • 13

    बस उन सभी के लिए इसे बाहर फेंक दें जो सोचते हैं कि कोई स्मृति से बाहर क्यों हो रहा है: मैं एक ऐसी परियोजना पर काम कर रहा हूं जो अक्सर स्मृति से बाहर हो जाता है और मुझे इसके लिए समाधान लागू करना पड़ता है।

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

    ट्रैवर्सल प्रक्रिया को गति देने के लिए, हम भौतिक स्मृति में जितना संभव हो उतना डेटा रखने की कोशिश करते हैं, लेकिन बाइनरी बढ़ने के साथ डेटा संरचनाएं बढ़ती हैं और हम इसे स्मृति में नहीं रख सकते हैं (लक्ष्य एक जावा ढेर का उपयोग करना है 256 मीटर से अधिक)। तो मैं क्या करूं?

    मैंने लिंक्डलिस्ट, हैशटेबल इत्यादि के डिस्क-समर्थित संस्करण बनाए हैं। ये उनके समकक्षों के लिए ड्रॉप-इन प्रतिस्थापन हैं और सभी समान इंटरफेस को लागू करते हैं ताकि वे बाहरी दुनिया से समान दिखें।

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

    जावा जावा में स्मृति से बाहर होने के कारणों की पूरी तरह से कारण हैं - इन कारणों में से अधिकांश की जड़ या तो दोनों में से एक है: 1. ऐप संसाधन बाधित मशीन पर चलाता है (या संसाधन को सीमित करने के प्रयास ढेर आकार सीमित करके उपयोग) 2. ऐप को बस बड़ी मात्रा में स्मृति की आवश्यकता होती है (छवि संपादन का सुझाव दिया गया था, लेकिन ऑडियो और वीडियो के बारे में कैसे? मेरे मामले में कंपेलरों के बारे में क्या? गैर-अस्थिर भंडारण के बिना दीर्घकालिक डेटा कलेक्टरों के बारे में कैसे?)

    -बिट

    +0

    +1। – sleske

    7

    यह पकड़ने के लिए संभव है एक OutOfMemoryError (यह एक Error, न कि एक ०१२३५३४६१८२८ है), लेकिन आपको अवगत होना चाहिए कि परिभाषित व्यवहार प्राप्त करने का कोई तरीका नहीं है।
    इसे पकड़ने की कोशिश करते समय आप एक और आउटऑफमेरी एरर भी प्राप्त कर सकते हैं।

    तो स्मृति जागरूक कैश बनाने/उपयोग करने का बेहतर तरीका है। वहाँ कुछ ढांचे हैं (उदाहरण: JCS), लेकिन आप आसानी से SoftReference का उपयोग कर अपना खुद का निर्माण कर सकते हैं।here का उपयोग करने के बारे में एक छोटा सा लेख है। अधिक जानकारी प्राप्त करने के लिए आलेख में दिए गए लिंक का पालन करें।

    +2

    "परिभाषित व्यवहार प्राप्त करने का कोई तरीका नहीं है": क्योंकि 'OutOfMemoryError' कहीं भी फेंक दिया जा सकता है, जिसमें ऐसे स्थान शामिल हैं जो आपके प्रोग्राम को असंगत स्थिति में छोड़ सकते हैं। Http://stackoverflow.com/questions/8728866/no-throw-virtualmachineerror- गारंटी – Raedwald

    2

    शायद कम से कम एक अच्छा समय एक OutOfMemoryError को पकड़ने के लिए है, जब आप विशेष रूप से कुछ है कि जिस तरह से बहुत बड़ा हो सकता है का आवंटन किया गया है:

    public static int[] decode(InputStream in, int len) throws IOException { 
        int result[]; 
        try { 
        result = new int[len]; 
        } catch (OutOfMemoryError e) { 
        throw new IOException("Result too long to read into memory: " + len); 
        } catch (NegativeArraySizeException e) { 
        throw new IOException("Cannot read negative length: " + len); 
        } 
        ... 
    } 
    
    +0

    क्या यह कोड भरोसेमंद काम करता है? मेरे पास वास्तव में यह मामला है, लेकिन मैं वास्तव में ऐप को क्रैश नहीं करना चाहता हूं। मुझे लगता है कि विकल्प यह है कि (लेन> कुछ कॉन्सर्वेटिव साइज) नए IOException ("बहुत लंबा") फेंक देते हैं; – Quantum7

    +3

    यह दृष्टिकोण सी ++ में अच्छी तरह से काम करता है, लेकिन मुझे जावा में इतना अच्छा संदेह नहीं है, क्योंकि 'new' और' OutOfMemoryError' के बीच कनेक्शन अप्रत्यक्ष है। अगर आवंटन केवल स्मृति में फिट बैठता है, तो कुछ समय बाद एक रहस्यमय 'आउटऑफमेमरी एरर' हो सकता है। – Raedwald

    संबंधित मुद्दे