2008-09-30 15 views
14

हमारे कार्यक्रमों में से एक को कभी-कभी उपयोगकर्ता की मशीन पर OutOfMemory त्रुटि मिल रही है, लेकिन निश्चित रूप से जब मैं इसका परीक्षण नहीं कर रहा हूं। मैंने इसे जेपीरोफाइलर के साथ चलाया (10 दिनों के मूल्यांकन लाइसेंस पर क्योंकि मैंने इसे पहले कभी नहीं उपयोग किया है), और हमारे कोड उपसर्ग पर फ़िल्टरिंग, कुल आकार और उदाहरणों की संख्या में सबसे बड़ा हिस्सा एक विशेष साधारण वर्ग के 8000+ उदाहरण हैं ।मैं कैसे पता लगा सकता हूं कि मुक्त वस्तुओं पर क्या हो रहा है?

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

ये उदाहरण विभिन्न चरणों में विभिन्न संग्रहों में फंस गए हैं। मुझे लगता है कि तथ्य यह है कि वे एकत्रित कचरे नहीं हैं, इसका मतलब यह होना चाहिए कि संग्रह में से किसी एक के संदर्भ में कुछ हो रहा है ताकि वस्तुओं के संदर्भ में हो।

कोई सुझाव मैं संदर्भ में क्या हो रहा है यह पता लगा सकता हूं? मैं कोड में क्या देखना है, इसके साथ ही जेपीआरओफ़ाइलर में इसे खोजने के तरीकों के बारे में सुझाव ढूंढ रहा हूं।

+0

यदि आप एक मुफ्त प्रोफाइलर की खोज करते हैं, तो मेरा सुझाव है कि आप http://jiprof.sourceforge.net/ देखें। शायद थोड़ा सा फैशन, कोई फैंसी गुई और इतने पर, लेकिन ज्यादातर मामलों के लिए काम कर रहा है। – dhiller

उत्तर

18

ढेर को डंप करें और इसका निरीक्षण करें।

मुझे यकीन है कि ऐसा करने के एक से अधिक तरीके हैं, लेकिन यहां एक सरल है। यह विवरण एमएस विंडोज के लिए है, लेकिन अन्य ऑपरेटिंग सिस्टम पर भी इसी तरह के कदम उठाए जा सकते हैं।

  1. यदि आपके पास पहले से नहीं है तो जेडीके इंस्टॉल करें। It comes with a bunch of neat tools.
  2. एप्लिकेशन प्रारंभ करें।
  3. ओपन टास्क मैनेजर और java.exe (या जो भी निष्पादन योग्य आप उपयोग कर रहे हैं) के लिए प्रक्रिया आईडी (पीआईडी) ढूंढें। यदि पीआईडी ​​डिफ़ॉल्ट रूप से नहीं दिखाए जाते हैं, तो उन्हें जोड़ने के लिए देखें> कॉलम का चयन करें ... का उपयोग करें।
  4. jmap का उपयोग करके ढेर को डंप करें।
  5. आप उत्पन्न फ़ाइल पर jhat सर्वर प्रारंभ करें और http://localhost:7000 (डिफ़ॉल्ट पोर्ट 7000 है) करने के लिए अपने ब्राउज़र को खोलने
  6. । अब आप जिस प्रकार की रुचि रखते हैं उसे ब्राउज़ कर सकते हैं और उदाहरणों की संख्या, उनके संदर्भ में संदर्भ, इत्यादि जैसी जानकारी ब्राउज़ कर सकते हैं।

यहाँ एक उदाहरण है:

C:\dump>jmap -dump:format=b,file=heap.bin 3552 

C:\dump>jhat heap.bin 
Reading from heap.bin... 
Dump file created Tue Sep 30 19:46:23 BST 2008 
Snapshot read, resolving... 
Resolving 35484 objects... 
Chasing references, expect 7 dots....... 
Eliminating duplicate references....... 
Snapshot resolved. 
Started HTTP server on port 7000 
Server is ready. 

इस व्याख्या के लिए, यह array type nomenclature जावा का उपयोग करता है में से कुछ को समझने के लिए उपयोगी है - जानते हुए भी तरह कि वर्ग [Ljava.lang.Object; वास्तव में ऑब्जेक्ट का एक ऑब्जेक्ट है []

+1

'jmap' के साथ डंप लेने पर सावधान रहें: आपको उस jvap' को चलाने वाले उपयोगकर्ता के रूप में' jmap' चलाने की आवश्यकता हो सकती है, जिसे आप कनेक्ट कर रहे हैं। [यह] देखें (http://stackoverflow.com/a/2943651/580412)। – phs

2

स्थिर कंटेनरों के लिए नजर रखें। एक स्थिर कंटेनर में कोई भी वस्तु तब तक रहेगी जब तक वर्ग लोड हो।

संपादित करें: WeakReference पर गलत टिप्पणी हटा दी गई है।

0

यदि आपको कचरा एकत्रित भाषा में ओओएम त्रुटियां मिल रही हैं, तो आमतौर पर इसका मतलब है कि कुछ स्मृति को कलेक्टर द्वारा जिम्मेदार नहीं माना जाता है। हो सकता है कि आपके ऑब्जेक्ट्स गैर-जावा संसाधन रखें? यदि ऐसा है, तो उनके पास यह सुनिश्चित करने के लिए किसी प्रकार की 'करीबी' विधि होनी चाहिए कि संसाधन जारी किया गया हो, भले ही जावा ऑब्जेक्ट जल्द ही एकत्र नहीं किया गया हो।

2

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

यह भी ध्यान रखें कि आप ओओएमई प्राप्त कर सकते हैं क्योंकि जीसी पर्याप्त स्मृति एकत्र करने में असफल रहा, वास्तव में वस्तु अनुरोध के लिए पर्याप्त होने के बावजूद। अन्यथा प्रदर्शन जमीन पर पीस जाएगा।

3

वहां कोई चांदी की बुलेट नहीं है, आपको उन अनियंत्रित वस्तुओं को रखने वाले संग्रहों की पहचान करने के लिए प्रोफाइलर का उपयोग करना होगा और कोड को उस स्थान पर ढूंढना होगा जहां उन्हें हटा दिया जाना चाहिए था। जैसा कि जेस्पर ने कहा, स्थिर संग्रह देखने के लिए पहली जगह है।

5

मैं आपकी कक्षाओं में संग्रह (विशेष रूप से स्थिर) देखता हूं (हैश मैप्स शुरू करने के लिए एक अच्छी जगह है)। जब तक HashMap या कुछ अन्य संग्रह है कि वस्तु यह कचरा एकत्र नहीं किया जाएगा के लिए एक संदर्भ के रूप में

Map<String, Object> map = new HashMap<String, Object>(); // 1 Object 
String name = "test";    // 2 Objects 
Object o = new Object();   // 3 Objects 
map.put(name, o);     // 3 Objects, 2 of which have 2 references to them 

o = null;       // The objects are still being 
name = null;      // referenced by the HashMap and won't be GC'd 

System.gc();      // Nothing is deleted. 

Object test = map.get("test"); // Returns o 
test = null; 

map.remove("test");    // Now we're down to just the HashMap in memory 
            // o, name and test can all be GC'd 

: उदाहरण के लिए इस कोड को ले लो।

+0

यदि पहले System.gc() के बाद "मानचित्र" का कोई और संदर्भ नहीं था, तो क्या यह कचरा एकत्र नहीं किया जाएगा? –

+0

हां, यदि कुछ और हैश मैप का संदर्भ नहीं देता है तो यह जीसीएड होने योग्य होगा। – 18Rabbit

+0

यह बदल सकता है, लेकिन क्या JVM system.gc कॉल को अनदेखा नहीं करता है और जब भी ऐसा लगता है तो इसे करें? – tloach

1

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

दो महत्वपूर्ण सबक यह रेखांकित कर रहे हैं:

1) अंतिम तरीकों जीसी क्या जब यह वस्तु culls करने के लिए कहता हूं, लेकिन यह ऐसा करने के लिए यह नहीं पूछता है, और न ही वहाँ की मांग करने के लिए एक रास्ता है यह करता है

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

अस्वीकरण: मुझे पता है कि अन्य उत्तरों ने इसका उल्लेख किया है, लेकिन मैं अधिक जानकारी देने की कोशिश कर रहा हूं।

+0

मुझे लगता है कि यदि किसी दायरे से बाहर निकलता है तो आपको किसी ऑब्जेक्ट के संदर्भ को बाहर करने की आवश्यकता नहीं है। –

+0

पी में। 24 "ब्लॉच" प्रभावी जावा "आइटम 6: अप्रचलित ऑब्जेक्ट संदर्भों को हटा दें, बुरी तरह कार्यान्वित स्टैक का एक उदाहरण है जहां इसके तत्व ऑब्जेक्ट [] तत्वों में कैश किए जाते हैं, लेकिन पॉप() को कॉल करते समय उन्हें तत्व सरणी से कभी नहीं हटाया जाता है। –

9

एक्लिप्स मेमोरी विश्लेषक का प्रयास करें। यह आपको प्रत्येक ऑब्जेक्ट के लिए दिखाएगा कि यह जीसी रूट से कैसे जुड़ा हुआ है - एक ऑब्जेक्ट जो कचरा नहीं है क्योंकि यह जेवीएम द्वारा आयोजित किया जाता है।

Eclipse MAT कैसे काम करता है, इस बारे में अधिक जानकारी के लिए http://dev.eclipse.org/blogs/memoryanalyzer/2008/05/27/automated-heap-dump-analysis-finding-memory-leaks-with-one-click/ देखें।

1

मैंने जावा 1.5 पर प्रदर्शन अनुकूलन के लिए योरकिट जावा प्रोफाइलर (http://www.yourkit.com) का उपयोग किया है। इसमें स्मृति खंडों पर काम करने के तरीके पर एक अनुभाग है। मुझे यह उपयोगी लगता है।

http://www.yourkit.com/docs/75/help/performance_problems/memory_leaks/index.jsp

आप एक 15 दिन eval प्राप्त कर सकते हैं: http://www.yourkit.com/download/yjp-7.5.7.exe

बीआर,
~ एक

1

संग्रह पहले ही उल्लेख किया गया था।एक और कठिन खोज स्थान यह है कि यदि आप एकाधिक क्लासलोडर्स का उपयोग करते हैं, क्योंकि पुराना क्लासलोडर कचरा होने में असमर्थ हो सकता है जब तक कि सभी संदर्भ नहीं चले जाते।

भी सांख्यिकी की जांच करें - ये खराब हैं। लॉगिंग फ्रेमवर्क चीजों को खुला रख सकते हैं जो कस्टम एपेंडर में संदर्भ रख सकते हैं।

क्या आपने समस्या का समाधान किया?

+1

नहीं, मुझे बंद कर दिया गया। तो यह मेरी समस्या नहीं है। –

1

कुछ सुझाव:

  • असीमित कैश के रूप में इस्तेमाल नक्शे, खासकर जब स्थिर सर्वर क्षुधा में
  • ThreadLocals, क्योंकि सूत्र आमतौर पर मर जाते हैं, तो ThreadLocal मुक्त नहीं है
  • होना शामिल तार (Strings.intern()), जिसके परिणामस्वरूप पर्मस्पेस
संबंधित मुद्दे

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