2008-10-03 8 views
9

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

मेरी रूपरेखा आवेदन के स्क्रीनशॉट जाना लिए here

उत्तर

5

क्या आप गतिशील रूप से फ्लाई पर नए वर्ग बना रहे हैं?

आपकी सहायता के लिए धन्यवाद। मुझे पता चला कि समस्या क्या है। मेरी कक्षाओं में से एक में, मैं एक एक्सएमएल स्ट्रिंग बनाने के लिए जैक्सबी का उपयोग कर रहा था। ऐसा करने में, जेएक्सबी ने एक नई कक्षा बनाने के प्रतिबिंब का संकेत दिया।

JAXBContext context = JAXBContext.newInstance(this.getClass()); 

तो हालांकि जैक्सबीनटेक्स्ट ढेर में चारों ओर नहीं कह रहा था, कक्षाएं लोड की गई थीं।

मैंने अपना प्रोग्राम फिर से चलाया है, और मुझे लगता है कि मैं एक सामान्य पठार देखता हूं।

+6

मैं आप से पूछना सकते हैं कि कैसे आप नए वर्ग के निर्माण से छुटकारा मिला? मैं इस समस्या से लड़ रहा हूं और मैं आपके समाधान का प्रयास करना चाहता हूं। - धन्यवाद – Ytsejammer

0

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

पुराने कोड में, एक श्रोता संबंध "श्रोता" ऑब्जेक्ट को आसपास रहने का कारण बनता है। मैं पुराने टूलकिट्स या उन लोगों को देखता हूं जो कई revs के माध्यम से नहीं किया गया है। बाद में जेडीके पर चलने वाली किसी भी लंबी-मौजूदा लाइब्रेरी संदर्भ ऑब्जेक्ट्स के बारे में जानती है जो "श्रोता निकालें" के लिए आवश्यकता को हटा देती है।

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

स्विंग या जेडीके श्रोताओं के बारे में चिंता न करें, उन्हें सभी संदर्भों का उपयोग करना चाहिए ताकि आपको ठीक होना चाहिए।

3

जब तक मैं गलत समझ नहीं पाता, हम यहां लोड कक्षाओं में देख रहे हैं, उदाहरण नहीं।

जब आपका कोड पहले कक्षा का संदर्भ देता है, तो JVM में क्लासलोडर बाहर जाता है और कक्षा के बारे में जानकारी को .class फ़ाइल या इसी तरह से प्राप्त करता है।

मुझे यकीन नहीं है कि यह किस श्रेणी के तहत कक्षा को उतार देगा। निश्चित रूप से इसे किसी भी वर्ग को स्थिर जानकारी के साथ कभी भी उतारना नहीं चाहिए।

तो मैं आपके पैटर्न की तरह लगभग एक पैटर्न की अपेक्षा करता हूं, जहां आपका आवेदन चलता है, यह क्षेत्रों में जाता है और नए वर्गों का संदर्भ देता है, इसलिए लोड किए गए वर्गों की संख्या बढ़ जाती है।

हालांकि, दो बातें मेरे लिए अजीब लगता है:

  1. क्यों यह इतना रैखिक है?
  2. यह पठार क्यों नहीं है?

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

क्या आप गतिशील रूप से फ्लाई पर नई कक्षाएं बना रहे हैं?

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

आपको यह पता लगाने की आवश्यकता है कि इन वर्गों को क्या लोड किया जा रहा है।

4

आप की तरह इस व्यवहार को समझने में उपयोग की जा करने के लिए कुछ हॉटस्पॉट झंडे खोज सकते हैं:

  • -XX: + TraceClassLoading
  • -XX: + TraceClassUnloading

यह एक अच्छा संदर्भ है :

http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

4

मैं शर्त लगाता हूं कि आपकी समस्या बाइटकोड पीढ़ी से संबंधित है।

कई पुस्तकालय रनटाइम पर नए वर्गों के लिए बाइटकोड उत्पन्न करने के लिए CGLib, BCEL, Javasist या Janino का उपयोग करते हैं और फिर उन्हें नियंत्रित क्लासलोडर से लोड करते हैं। इन वर्गों को जारी करने का एकमात्र तरीका क्लासलोडर के सभी संदर्भों को जारी करना है।

चूंकि प्रत्येक वर्ग द्वारा क्लासलोडर आयोजित किया जाता है, इसका मतलब यह भी है कि आपको सभी वर्गों के संदर्भों को भी जारी नहीं करना चाहिए [1]। आप इन्हें एक सभ्य प्रोफाइलर के साथ पकड़ सकते हैं (मैं आपकेकिट का उपयोग करता हूं - एक ही बनाए गए आकार के साथ एकाधिक क्लासलोडर उदाहरणों की खोज)

एक पकड़ यह है कि JVM डिफ़ॉल्ट रूप से कक्षाएं अनलोड नहीं करता है (कारण पीछे की संगतता है - जो लोग मानते हैं । (गलत तरीके से) है कि स्थिर initializers केवल एक बार निष्पादित किया जाएगा सच्चाई यह है कि वे हर बार एक वर्ग भरी हुई है निष्पादित हो रहा है) उतराई सक्षम करने के लिए, आप पास करना चाहिए कुछ निम्नलिखित विकल्पों का उपयोग करें:।

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled 

(के साथ परीक्षण किया जेडीके 1.5)

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

यह भी देखें:

  1. http://blogs.oracle.com/watt/resource/jvm-options-list.html
  2. http://blogs.oracle.com/jonthecollector/entry/presenting_the_permanent_generation
  3. http://forums.sun.com/thread.jspa?messageID=2833028
+0

यहां तक ​​कि जेवीएम java.lang.reflect.Proxy के लिए कक्षाएं उत्पन्न करेगा और फील्ड.get/set, Method.invoke और Constructor.newInstance (IIRC) को गर्म कर देगा। –

+0

हां, आप सही हैं, फिर भी इन जेनरेट किए गए वर्ग प्रतिबिंब परत में कैश किए जाते हैं, इसलिए परमजन लीक का कारण नहीं होना चाहिए। – ddimitrov

0

उपयोग Eclipse Memory Analyzer डुप्लिकेट किए गए वर्गों और मेमोरी लीक के लिए जाँच करने के लिए। ऐसा हो सकता है कि एक ही कक्षा एक से अधिक बार लोड हो जाती है।

सादर, Markus

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