2012-01-03 2 views
14

मेरे पास एक प्रक्रिया है (जिसे हर बार घड़ी-कुत्ते द्वारा शुरू किया जाता है, यह किसी कारण से रुक जाता है), जो आम तौर पर 200 एमबी मेमोरी का उपयोग करता है। एक बार मैंने देखा कि यह स्मृति को खा रहा है - मेमोरी के उपयोग के बारे में 1.5-2 जीबी, जिसका निश्चित रूप से कहीं "स्मृति रिसाव" होता है (उद्धरणों में "मेमोरी रिसाव", क्योंकि यह वास्तविक स्मृति रिसाव नहीं है - आवंटित स्मृति की तरह, कभी मुक्त नहीं हुआ और पहुँच योग्य नहीं - कृपया ध्यान दें, कि केवल स्मार्ट संकेत उपयोग किया जाता है तो, मैं या क्योंकि उच्च के कुछ बहुत बड़ा कंटेनर के बारे में सोचना (मैं भी नहीं मिला) कुछ इस तरह)क्या यह पता लगाने का कोई तरीका है कि प्रक्रिया के किस हिस्से ने अधिकांश मेमोरी का उपयोग किया, केवल जेनरेट की गई कोर फ़ाइल को देख रहा है?

बाद में, प्रक्रिया दुर्घटनाग्रस्त हो गया,। स्मृति उपयोग और कोर डंप उत्पन्न हुआ - लगभग 2 जीबी। लेकिन समस्या यह है कि मैं इस मुद्दे को पुन: उत्पन्न नहीं कर सकता, इसलिए valgrind यहां मदद नहीं करेगा (मुझे लगता है)। यह बहुत ही कम होता है और मैं इसे "पकड़ नहीं सकता"।

तो, मेरा सवाल है - क्या प्रक्रिया का कौन सा हिस्सा पता लगाने के लिए एक्सई और कोर फ़ाइल का उपयोग करके कोई तरीका है, क्या अधिकांश मेमोरी का उपयोग किया गया है?

मैंने gdb के साथ कोर फ़ाइल पर एक नज़र डाली, कुछ भी असामान्य नहीं है। लेकिन कोर बड़ा है, इसलिए कुछ होना चाहिए। क्या हुआ है, यह समझने का एक चालाक तरीका है, या केवल अनुमान लगाने में मदद मिल सकती है (लेकिन इस तरह के बड़े exe .., 12 धागे, लगभग 50-100 (अधिक हो सकता है) कक्षाएं, इत्यादि आदि)

यह एक है C++ आवेदन, RHEL5U3 पर चल रहा है।

+1

एक्सके के साथ सी ++ टैग के लिए 5 अनुयायियों के साथ अपने coredump टैग का व्यापार करने पर विचार करें? अनुयायियों। सौभाग्य। – shellter

+0

मैंने इस बारे में सोचा, लेकिन मुझे आश्चर्य हुआ कि यह सही है या नहीं। मैं इसे आज़मा दूंगा :) –

+1

शुभकामनाएं; ये बग चूसते हैं। –

उत्तर

12

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

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

अद्यतन

अपने coredump वैध कॉल स्टैक है, तो आप अपने कार्यों का निरीक्षण के साथ शुरू कर सकते हैं। असामान्य कुछ भी खोजें। जांचें कि क्या कॉल स्टैक के शीर्ष के पास मेमोरी आवंटन बहुत अधिक अनुरोध नहीं करते हैं। कॉल स्टैक फ़ंक्शंस में संभावित अनंत लूप की जांच करें।

शब्द "केवल स्मार्ट पॉइंटर्स का उपयोग" मुझे डराता है। यदि इन स्मार्ट पॉइंटर्स का महत्वपूर्ण हिस्सा साझा पॉइंटर्स (shared_ptr, intrusive_ptr, ...) हैं, तो विशाल कंटेनरों की खोज करने के बजाय, साझा पॉइंटर चक्रों की खोज करना उचित है।

अद्यतन 2

कोशिश निर्धारित करने के लिए जहां अपने ढेर corefile (brk मूल्य) में समाप्त होता है। Gdb के तहत coredumped प्रक्रिया चलाएं और pmap कमांड (अन्य टर्मिनल से) का उपयोग करें। जीडीबी को यह मान भी पता होना चाहिए, लेकिन मुझे नहीं पता कि इसे कैसे पूछना है ... यदि अधिकांश प्रक्रिया 'मेमोरी brk से ऊपर है, तो आप बड़ी मेमोरी आवंटन (संभवतः, std :: वेक्टर) द्वारा अपनी खोज को सीमित कर सकते हैं।

मौजूदा coredump के ढेर क्षेत्र में लीक पाने की संभावना को बेहतर करने के लिए, कुछ कोडिंग किया जा सकता है (मैं इसे अपने आप सिर्फ एक सिद्धांत नहीं किया,):

  • पढ़ें coredump फ़ाइल, प्रत्येक मान की व्याख्या एक सूचक के रूप में (कोड सेगमेंट, अनचाहे मूल्यों और गैर-ढेर क्षेत्र में पॉइंटर्स को अनदेखा करें)। सूची को क्रमबद्ध करें, आसन्न तत्वों के मतभेदों की गणना करें।
  • इस बिंदु पर पूरी स्मृति कई संभावित संरचनाओं में विभाजित है। संरचना के आकार के हिस्टोग्राम की गणना करें, किसी भी महत्वहीन मूल्य को छोड़ दें।
  • पॉइंटर्स और संरचनाओं के पते के अंतर की गणना करें, जहां ये पॉइंटर्स संबंधित हैं। प्रत्येक संरचना आकार के लिए, पॉइंटर्स विस्थापन के हिस्टोग्राम की गणना करें, फिर से किसी भी महत्वहीन मूल्य को छोड़ दें।
  • अब आपके पास संरचना प्रकारों का अनुमान लगाने या संरचनाओं के निर्देशित ग्राफ को बनाने के लिए पर्याप्त जानकारी है। इस ग्राफ के स्रोत नोड्स और चक्र खोजें। आप इस ग्राफ को "list “cold” memory areas" में भी देख सकते हैं।

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

+2

'स्ट्रिंग कोर' चलाना कुछ सुराग भी प्रदान कर सकता है। –

+0

वेंक, मैं हेक्स संपादक के साथ और 'स्ट्रिंग कोर' के साथ कोशिश करूंगा .. लेकिन कोर विशाल है - 2 जीबी: एक्स लेकिन विचारों के लिए धन्यवाद। कॉल स्टैक के बारे में - हाँ, प्रत्येक थ्रेड के लिए अच्छा कॉल स्टैक है (11 धागे और परियोजना बड़ी है), लेकिन वहाँ है वहां कुछ भी संदिग्ध नहीं है: \ पॉइंटर्स के बारे में - हां, फिर, उनमें से अधिकतर पीटीआर साझा किए जाते हैं, लेकिन मैंने उन्हें चेक किया है, सब कुछ भी अच्छा लगता है। मुझे ऐसी समस्याओं से नफरत है, जब वे (आसानी से) पुनरुत्पादित नहीं होते हैं: डी धन्यवाद फिर से :) –

+0

'स्ट्रिंग्स 'के साथ कुछ भी दिलचस्प नहीं - एलओएल, लगभग 550k लाइनें: डी –

2

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

+0

एचएम, मुझे यह उल्लेख करना था कि मेरे प्रश्न, मैं संपादित करूंगा। अतिरिक्त है - हम केवल स्मार्ट पॉइंटर्स का उपयोग करते हैं, इसलिए यदि आवंटित स्मृति है, जो मुक्त नहीं है, तो यह अभी भी पहुंच योग्य होगा। –

3

एक बार मैंने देखा कि यह स्मृति को खा रहा है - स्मृति के उपयोग के साथ के बारे में 1.5-2GB

अक्सर ऐसा गलती से हुआ पाश भटक जाने का एक अंतिम परिणाम होगा। कुछ की तरह: ग़लती से कुछ शर्तों के तहत झूठे रिटर्न

size_t size = 1; 
p = malloc(size); 
while (!enough_space(size)) { 
    size *= 2; 
    p = realloc(p, size); 
} 
// now use p to do whatever 

तो enough_space(), अपनी प्रक्रिया जल्दी से सभी स्मृति उपलब्ध उपभोग करने के लिए बड़ा हो जाएगा।

केवल स्मार्ट संकेत

उपयोग किया जाता है जब तक आप पर नियंत्रण सभी कोड बयान से ऊपर, प्रक्रिया में जुड़ा हुआ झूठी है। त्रुटि लूप libc, या कोई अन्य लाइब्रेरी के अंदर हो सकता है जिसका आपके स्वामित्व नहीं है।

केवल मदद मिल सकती है

कि काफी यह अनुमान लगा। Evgeny के जवाब में अनुमान लगाने में आपकी मदद करने के लिए अच्छे शुरुआती बिंदु हैं।

+0

सबसे दिलचस्प आपके कोड स्निपेट का हिस्सा अनंत लूप है। यह कई तरीकों से स्मृति रिसाव का कारण बन सकता है (सी या सी + कोड दोनों में)। और यह खोजने में काफी आसान है। –

+0

ऐसी कोई लूप नहीं - अधिकांश चीजें एसटीएल हैं। पॉइंटर्स के बारे में - नहीं, मैं प्रक्रिया के सभी स्रोतों को नियंत्रित नहीं करता हूं, लेकिन यह समस्या 'libc', या' occi', या किसी अन्य तीसरे पक्ष में होने वाली समस्या है, व्यापक रूप से उपयोग की जाने वाली लाइब्रेरी में। बिल्कुल असंभव नहीं है। धन्यवाद :) –

1

Valgrind संभावित रूप से कई संभावित त्रुटियां पायेगा, और यह उन सभी का विश्लेषण करने के लिए उपयुक्त है। आपको एक दमन फ़ाइल बनाने की आवश्यकता है, और इसे --suppressions=/path/to/file.supp की तरह उपयोग करें।प्रत्येक संभावित त्रुटि के लिए valgrind झंडे, या तो दमन फ़ाइल में एक खंड जोड़ें, या अपने प्रोग्राम को बदलें।

आपका प्रोग्राम Valgrind में धीमा चल रहा है, और इसलिए घटनाओं का समय अलग होगा, इसलिए आप अपनी त्रुटि को देखने के बारे में सुनिश्चित नहीं हो सकते हैं।

एलीओप नामक वाल्ग्रिंड के लिए एक जीयूआई है, लेकिन मैंने इसका अधिक उपयोग नहीं किया है।

+0

हाँ, मैंने पहले ही यह किया है, कुछ भी संदिग्ध नहीं है: \ मैं यह देखने के लिए इस विकल्प के साथ प्रयास करूंगा कि क्या होगा। धन्यवाद। –

+0

यह उस प्रश्न का समाधान नहीं करता है जिसे हालांकि पूछा गया था। – Owl

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

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