2009-03-18 9 views
43

काम पर, हमें "PermGen out of memory" अपवादों के साथ समस्या हो रही है, टीम ने निर्णय लिया है कि यह JVM में एक बग था - कोड की हॉट-तैनाती से संबंधित कुछ। कई विवरणों को बताने के बिना, उन्होंने इंगित किया कि गर्म तैनाती एक "कठिन समस्या" है, इतना कठिन है कि .NET अभी भी ऐसा नहीं करता है।गर्म तैनाती को "हार्ड समस्या" क्या बनाता है?

मुझे पक्षी के आंखों के दृश्य से गर्म तैनाती समझाते हुए बहुत से लेख मिलते हैं, लेकिन हमेशा तकनीकी विवरणों की कमी होती है। क्या कोई मुझे तकनीकी स्पष्टीकरण के लिए इंगित कर सकता है, और समझा सकता है कि गर्म तैनाती "कठिन समस्या" क्यों है?

+0

इस समुदाय विकी क्यों है? – Eddie

+2

सोचा कि अगर मैं कुछ अस्पष्ट छोड़ देता हूं तो इससे मदद मिल सकती है ... डिफ़ॉल्ट रूप से ऐसा करें, क्या यह बुरा शिष्टाचार है? –

+0

मजेदार: अभी एक बार फिर से पढ़ते समय एक विचार-ओ मिला, धन्यवाद! –

उत्तर

58

जब कोई वर्ग लोड होता है, तो कक्षा के बारे में विभिन्न स्थिर डेटा PermGen में संग्रहीत किया जाता है। जब तक इस कक्षा के उदाहरण के लिए एक लाइव संदर्भ मौजूद है, कक्षा के उदाहरण को कचरा नहीं बनाया जा सकता है।

मेरा मानना ​​है कि समस्या का हिस्सा यह है कि जीसी को परम जीन से पुरानी कक्षा के उदाहरणों को हटा देना चाहिए या नहीं। आम तौर पर, हर बार जब आप गर्म तैनाती करते हैं, तो पर्मजेन मेमोरी पूल में नए वर्ग के उदाहरण जोड़े जाते हैं, और पुराने, अब अप्रयुक्त, आमतौर पर हटाए जाते हैं। डिफ़ॉल्ट रूप से, सूर्य JVMs PermGen में कचरा संग्रह नहीं चलाएगा, लेकिन इसे वैकल्पिक "जावा" कमांड तर्कों के साथ सक्षम किया जा सकता है।

इसलिए, यदि आप पर्याप्त समय पर गर्म तैनाती करते हैं, तो आप अंततः अपने परमजेन स्पेस को समाप्त कर देंगे।

अपने वेब एप्लिकेशन बंद नहीं करता है, तो पूरी तरह से जब undeployed - अगर यह एक धागा चल छोड़ देता है, उदाहरण के लिए - तो क्लास है कि वेब एप्लिकेशन द्वारा उपयोग उदाहरणों के सभी PermGen अंतरिक्ष में पिन किया जाएगा। आप पुन: नियोजित करते हैं और अब पर्मजेन में लोड किए गए इन सभी क्लास उदाहरणों की एक और पूरी प्रति है। आप Undeploy और थ्रेड जारी रहता है, Permgen में कक्षा के उदाहरणों के एक और सेट पिन। आप प्रतियों के पूरे नेट सेट को फिर से तैनात और लोड करते हैं ... और अंत में आपका पर्मोजेन भर जाता है। हाल ही में एक सूर्य JVM करने के लिए आदेश तर्क की आपूर्ति PermGen में और वर्गों के जीसी सक्षम करने के लिए

  • :

    आप कभी-कभी इसे ठीक कर सकते हैं। यही कारण है: -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

  • एक अलग JVM कि एक निश्चित आकार PermGen या इस्तेमाल नहीं करता है का उपयोग करना है कि लोड कक्षाएं

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

कक्षा लोडर लीक के कारण भी यह समस्या को ठीक नहीं करेगा। (साथ ही साथ कुछ मामलों में बहुत से प्रशिक्षित तार भी हैं।)

अधिक के लिए निम्न लिंक देखें (दो बोल्ड वाले लोगों को समस्या के हिस्से को चित्रित करने के लिए अच्छे चित्र हैं)।

+1

एडी - कक्षाओं को रखने के लिए कारण नहीं है क्योंकि "पुरानी" कक्षा परिभाषा के साथ पहले से ही मौजूदा वस्तुओं को खटखटाया जा रहा है? –

+0

@ एडी: अधिकांश लिंक क्लासलोडर आर्किटेक्चर की बजाय स्मृति से संबंधित हैं जो समझने में सबसे उपयोगी होगा कि गर्म-तैनाती क्यों समस्या है। स्मृति समस्या वर्कअराउंड का एक परिणाम है। – OscarRyz

+0

थ्रेड चलाने के बारे में सिर्फ एक नोट: जब मैंने गलती से फिर से तैनाती पर सोने के लिए धागा छोड़ा, तो थ्रेड जागने के बाद इसे नोक्लास डीफफाउंड (कक्षाएं बेरोजगार) फेंक दी गईं, और फिर (निश्चित रूप से) मृत्यु हो गई। इसकी मृत्यु के बाद पर्मजेन जीसीड होने के लिए ठीक होना चाहिए। –

6

सामान्य शब्दों में समस्या जावा के सुरक्षा मॉडल है कि वास्तव में रोकने का प्रयास करता है एक वर्ग है कि पहले से लोड किया जा चुका है फिर से लोड किया जा रहा है।

बेशक जावा ने शुरुआत के बाद से गतिशील वर्ग लोडिंग का समर्थन किया है, क्लास पुनः लोड करना मुश्किल है।

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

तो, जावा जिस तरह से जावा की कल्पना की गई थी (और मैं परिणाम में .NET CLR मानता हूं, क्योंकि यह जेवीएम में अत्यधिक "प्रेरित" था) पहले से लोड कक्षा को उसी वीएम को फिर से लोड करने से रोकने के लिए था।

उन्होंने इस "फीचर" को ओवरराइड करने के लिए एक तंत्र की पेशकश की। क्लासलोडर, लेकिन क्लास लोडर के लिए नियम फिर से थे, उन्हें एक नया वर्ग लोड करने का प्रयास करने से पहले "पैरेंट" क्लासलोडर को अनुमति मांगी जानी चाहिए, अगर माता-पिता पहले से ही कक्षा को लोड कर चुके हैं, तो नई कक्षा को नजरअंदाज कर दिया जाता है।

उदाहरण के लिए मैं classloaders कि LDAP या आरडीबीएमएस से कक्षाओं लोड

गर्म तैनाती जब अनुप्रयोग सर्वर जावा ईई के लिए मुख्यधारा हो गया (और भी सूक्ष्म पात्र की आवश्यकता बनाने के जावा दुनिया में एक जरूरत बन जाता इस्तेमाल किया है वसंत की तरह इस तरह के बोझ से बचने के लिए)।

प्रत्येक संकलन ड्राइव के बाद किसी भी पागल ड्राइव के बाद पूरे ऐप सर्वर को पुनरारंभ करना।

तो ऐप सर्वर प्रदाता, इस "कस्टम" वर्ग लोडर को गर्म तैनाती में मदद करने के लिए, और कॉन्फ़िगरेशन फ़ाइल का उपयोग करने के लिए, उस व्यवहार को सेट करते समय अक्षम किया जाना चाहिए। लेकिन ट्रेडऑफ आपको विकास में बहुत सारी स्मृति का उपयोग करना है। तो ऐसा करने का अच्छा तरीका हर 3 - 4 तैनाती को पुनरारंभ करना है।

यह अन्य भाषाओं के साथ नहीं होता है जो शुरुआत से ही अपनी कक्षाओं को लोड करने के लिए डिज़ाइन किए गए थे।

उदाहरण के लिए रूबी में, आप रनिंग क्लास में विधियों को भी जोड़ सकते हैं, रनटाइम पर एक विधि ओवरराइड कर सकते हैं या यहां तक ​​कि एक अद्वितीय विशिष्ट ऑब्जेक्ट में एक विधि भी जोड़ सकते हैं।

इन प्रकार के वातावरण में व्यापार निश्चित रूप से स्मृति और गति है।

मुझे उम्मीद है कि इससे मदद मिलती है।

संपादित

मैं इस उत्पाद कुछ समय पहले कि वादा किया पुनः लोड संभव के रूप में सरल बनाया जाए कि मिल गया है। जब मैंने पहली बार यह जवाब लिखा था, तो मुझे लिंक याद नहीं आया, और मैं करता हूं।

यह JavaRebel from ZeroTurnaround

+0

आपके सिर में क्या गड़बड़ है, आह? इसलिए जावा को रनटाइम पर कक्षाएं लोड करने के लिए डिज़ाइन नहीं किया गया था, ओह? यही कारण है कि इसकी शुरुआत कक्षा सेforName() है? –

+0

ऑस्कर ने व्लादिमीर को लिखा नहीं है। उन्होंने लिखा कि जावा को रनटाइम पर कक्षाओं को बदलने के लिए डिज़ाइन नहीं किया गया था। –

+0

क्लासलोडर क्लास संस्करण 1 से है। रनटाइम पर कक्षाओं को प्रतिस्थापित करने के लिए डिज़ाइन नहीं किया गया है? इसके अलावा, सुरक्षा के पास पर्मजेन ओओएम के साथ कुछ लेना देना नहीं है। पर्मजेन पर सीमा सूर्य जेवीएम का सिर्फ एक बुरा कार्यान्वयन विवरण है। –

3

सूर्य JVM अंतरिक्ष तय PermGen गया है, और अंत में यह सब भस्म है => OOM (हाँ, जाहिरा तौर पर classloader से संबंधित कोड में एक बग के कारण)।

यदि आप किसी अन्य विक्रेता के JVM (उदा। वेबलॉगिक एक) का उपयोग कर सकते हैं, तो यह गतिशील रूप से PermGen स्पेस को बढ़ाता है, ताकि आपको कभी भी अनुमति न हो।

+0

वहां रुको। यह 100% सच नहीं है। परम मणि समस्या न केवल जेवीएम और इसकी पुस्तकालयों से संबंधित है। खराब एप्लिकेशन भी PermGen त्रुटियों का कारण बन सकता है। इसके अलावा, गतिशील रूप से पेर्गन का विस्तार करना इसे हल करने से बिल्कुल अलग है। किसी भी वीएम में पर्याप्त समय प्रतीक्षा करें और समस्या होगी। – Antonio

+1

सही। फिर भी, गतिशील PermGen आपको अधिक गर्म तैनाती के समय जीवित रहने की अनुमति देता है। सूर्य जेवीएम में यह अक्सर पुनर्वितरण # 1: -E –

0

जावा का आप किस संस्करण का उपयोग कर रहे हैं? सूर्य 1.4.2 के शुरुआती दिनों में बग थे, लेकिन यह लंबे समय तक काम कर रहा है।
बीटीडब्ल्यू, आप अपनी टीम के नेतृत्व में समाचार कैसे तोड़ेंगे? क्या आप टीम का नेतृत्व कर रहे हैं?

+0

पर होता है यह वास्तव में 1.5 से नई समस्या है। या कम से कम मैं केवल 1.5 में भाग गया। –

+0

हम इस समस्या में 1.6 के साथ चल रहे हैं। मैं शायद इस पृष्ठ के लिए एक लिंक भेजकर मेरी टीम लीड में "इसे तोड़ दूंगा" :-P –

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