2008-08-11 43 views
16

तो, मुझे कुछ मदद चाहिए। मैं सी ++ में एक परियोजना पर काम कर रहा हूं। हालांकि, मुझे लगता है कि मैंने किसी भी तरह से मेरी ढेर को भ्रष्ट करने में कामयाब रहा है। एक ढेर डंप के साथ अपने सिस्टम परमेमोरी मैनेजमेंट, हीप भ्रष्टाचार, और सी ++

std::string hello = "Hello, world.\n"; 
/* exampleString = "Hello, world.\n" would work fine. */ 
exampleString = hello; 

दुर्घटनाओं: यह सच है कि मैं एक वर्ग के लिए एक std::string जोड़ा गया है और यह एक और std::string से एक मान निर्दिष्ट पर आधारित है। इसलिए मूल रूप से मुझे रोकना होगा और मेरे सभी कोड और मेमोरी प्रबंधन सामग्री के माध्यम से जाना होगा और पता लगाएं कि मैंने कहां खराब कर दिया है। कोडबेस अभी भी छोटा है (लगभग 1000 लाइनें), इसलिए यह आसानी से सक्षम है।

फिर भी, मैं इस तरह के सामान के साथ अपने सिर पर हूं, इसलिए मैंने सोचा कि मैं इसे वहां फेंक दूंगा। मैं एक लिनक्स सिस्टम पर हूं और valgrind के साथ घिरा हुआ है, और पूरी तरह से नहीं जानता कि मैं क्या कर रहा हूं, यह रिपोर्ट करता है कि std::string का विनाशक एक अवैध मुक्त था। मुझे Google खोज से 'हीप भ्रष्टाचार' शब्द प्राप्त करने के लिए प्रवेश करना होगा; इस तरह के सामान पर किसी भी सामान्य उद्देश्य लेख की भी सराहना की जाएगी।

(rm -rf ProjectDir से पहले में, सी # में फिर से कार्य करें: डी)

संपादित करें: मैं यह स्पष्ट नहीं किया है, लेकिन तरीके स्मृति समस्याओं के इन प्रकार के निदान के लिए एक सलाह है कि मैं क्या कर रहा हूँ के लिए पूछ रहे हैं। मुझे पता है कि std :: स्ट्रिंग सामान सही है, इसलिए मैंने ऐसा कुछ किया है (या एक बग, लेकिन चयन के साथ कोई समस्या नहीं है)। मुझे यकीन है कि मैं जिस कोड को लिखा है उसे देख सकता हूं और आप बहुत ही स्मार्ट लोगों को किसी भी समय समस्या नहीं देख पाएंगे, लेकिन मैं इस तरह के कोड विश्लेषण को अपने 'टूलबॉक्स' में जोड़ना चाहता हूं, जैसा कि यह था।

उत्तर

21

ये संभवतः समस्या को हल करने के लिए अपेक्षाकृत सस्ती तंत्र हैं:

  1. पर नजर रखें मेरी heap corruption question - मैं जवाब के साथ अद्यतन करने कर रहा हूँ के रूप में वे बाहर हिला। पहला new[] और delete[] को संतुलित कर रहा था, लेकिन आप पहले से ही ऐसा कर रहे हैं।
  2. valgrind अधिक जाने दें; यह एक उत्कृष्ट उपकरण है, और मैं केवल यह चाहता हूं कि यह विंडोज के तहत उपलब्ध था। मैं केवल आपके प्रोग्राम को लगभग आधे से धीमा कर देता हूं, जो कि विंडोज समकक्षों की तुलना में काफी अच्छा है।
  3. प्रतिस्थापन malloc/new के रूप में Google Performance Tools का उपयोग करने के बारे में सोचें।
  4. क्या आपने अपनी सभी ऑब्जेक्ट फाइलों को साफ़ कर लिया है और शुरू किया है? शायद आपकी मेक फाइल है ... "सबोपेटिमल"
  5. आप अपने कोड में assert() आईएनजी नहीं हैं। मुझे कैसे पता चलेगा कि इसे देखे बिना? फ्लॉसिंग की तरह, कोई भी assert() उनके कोड में पर्याप्त नहीं है। अपनी ऑब्जेक्ट्स के लिए एक सत्यापन फ़ंक्शन में जोड़ें और कॉल स्टार्ट और विधि अंत पर कॉल करें।
  6. क्या आप compiling -wall हैं? यदि नहीं, तो ऐसा करें।
  7. अपने आप को एक लिंट टूल जैसे PC-Lint खोजें। आपके जैसे एक छोटा ऐप PC-lint demo पृष्ठ में फिट हो सकता है, जिसका अर्थ है कि आपके लिए कोई खरीदारी नहीं है!
  8. जांचें कि आप उन्हें हटाने के बाद पॉइंटर्स को न्यूल कर रहे हैं। किसी को भी एक लापरवाही सूचक पसंद नहीं है। घोषित लेकिन unallocated पॉइंटर्स के साथ एक ही गग।
  9. सरणी का उपयोग बंद करो। इसके बजाय vector का उपयोग करें।
  10. कच्चे पॉइंटर्स का उपयोग न करें। smart pointer का उपयोग करें। auto_ptr का उपयोग न करें! वह बात है ... आश्चर्यजनक; इसके अर्थशास्त्र बहुत अजीब हैं। इसके बजाय, Boost smart pointers में से कोई एक चुनें, या the Loki library में से कुछ चुनें।
+2

+1, अच्छी सूची! हालांकि, मैं # 8 पर विवाद करूंगा - जबकि यह 'खराब' पहुंच को रोकता है, यह वास्तव में एक कोड गंध है जो मेरे अनुभव में खराब तर्क या खराब वस्तु जीवनकाल प्रबंधन को छुपाता है ... – Roddy

+0

इन दिनों, सी ++ के मानक में अपने स्मार्ट पॉइंटर्स हैं लाइब्रेरी, इसलिए उस के लिए बूस्ट या लोकी की कोई ज़रूरत नहीं है। लिनक्स के लिए –

0

जहाँ तक मैं आपका कोड बता सकता हूं वह सही है। उदाहरण मानना ​​एक स्ट्रिंग :: स्ट्रिंग है जिसमें आपके द्वारा वर्णित वर्ग स्कोप है, आपको इसे इस तरह से प्रारंभ/असाइन करने में सक्षम होना चाहिए। शायद कुछ और मुद्दा है? हो सकता है कि वास्तविक कोड का एक स्निपेट इसे संदर्भ में रखने में मदद करेगा।

प्रश्न: उदाहरण उदाहरण के साथ एक स्ट्रिंग ऑब्जेक्ट के लिए एक सूचक है?

1

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

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

1

आपका कोड जो मैं देख सकता हूं उसे कोई त्रुटि नहीं है। जैसा कि कहा गया है कि अधिक संदर्भ की आवश्यकता है।

यदि आपने पहले से ही कोशिश नहीं की है, तो gdb (gcc डीबगर) स्थापित करें और प्रोग्राम को संकलित करें -g। यह डीबगिंग प्रतीकों में संकलित होगा जो जीडीबी उपयोग कर सकते हैं। एक बार जब आपने gdb इंस्टॉल किया है तो इसे प्रोग्राम (gdb) के साथ चलाएं। This जीडीबी का उपयोग करने के लिए एक उपयोगी चीटशीट है।

बग का उत्पादन करने वाले फ़ंक्शन के लिए ब्रेकपॉइंट सेट करें, और देखें कि उदाहरण स्ट्रिंग का मान क्या है। उदाहरण के लिए जो भी पैरामीटर आप पास कर रहे हैं उसके लिए भी वही करें। यह कम से कम आपको बताएगा कि क्या std :: तार मान्य हैं।

मुझे पॉइंटर्स के बारे में अच्छी मार्गदर्शिका के लिए this article का उत्तर मिला।

1

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

इसके अलावा, मैंने वास्तव में std :: स्ट्रिंग समस्या को ठीक किया है। कैसे? एक सदिश के साथ इसे बदलकर, संकलन, फिर स्ट्रिंग को फिर से बदलना। यह लगातार वहां क्रैश हो रहा था, और यह तय किया गया कि यह ... हो सकता है। वहाँ कुछ बुरा है, और मुझे यकीन नहीं है कि क्या। मैं एक बार मैं मैन्युअल रूप से ढेर पर स्मृति को आबंटित की जाँच करने, हालांकि चाहता था:

this->map = new Area*[largestY + 1]; 
for (int i = 0; i < largestY + 1; i++) { 
    this->map[i] = new Area[largestX + 1]; 
} 

और इसे हटाने:

for (int i = 0; i < largestY + 1; i++) { 
    delete [] this->map[i]; 
} 
delete [] this->map; 

मैंने पहले सी ++ के साथ एक 2 डी सरणी आवंटित नहीं किया है। ऐसा लगता है कि काम करता है।

7

ओह, अगर आप जानना चाहते हैं कि समस्या को कैसे डिबग करना है, तो यह आसान है। सबसे पहले, एक मृत चिकन प्राप्त करें। फिर, start shaking it

गंभीरता से, मुझे इस प्रकार की बग को ट्रैक करने के लिए एक सतत तरीका नहीं मिला है। क्योंकि वहां कई संभावित समस्याएं हैं, इसलिए जाने के लिए एक सरल चेकलिस्ट नहीं है। हालांकि, मैं निम्नलिखित की सिफारिश करता हूं:

  1. डीबगर में आराम प्राप्त करें।
  2. डीबगर में चारों ओर ट्रामिंग करना शुरू करें यह देखने के लिए कि क्या आप कुछ भी पागल दिख सकते हैं। exampleString = hello; लाइन के दौरान क्या हो रहा है यह देखने के लिए विशेष रूप से जांचें।
  3. यह सुनिश्चित करने के लिए जांचें कि यह वास्तव में exampleString = hello; लाइन पर क्रैश हो रहा है, और कुछ संलग्न ब्लॉक से बाहर निकलने पर नहीं (जो विनाशकों को आग लग सकता है)।
  4. कोई भी पॉइंटर जादू जांचें जो आप कर सकते हैं। सूचक अंकगणित, कास्टिंग, आदि
  5. यह सुनिश्चित करने के लिए अपने सभी आवंटन और विध्वंसों की जांच करें (कोई डबल-डेलोकेशन नहीं)।
  6. सुनिश्चित करें कि आप किसी भी संदर्भ या पॉइंटर्स को स्टैक पर ऑब्जेक्ट्स पर वापस नहीं लौट रहे हैं।

भी कोशिश करने के लिए कई अन्य चीजें हैं। मुझे यकीन है कि कुछ अन्य लोग भी विचारों के साथ झुकाएंगे।

1

इसके अलावा, मैंने वास्तव में std :: स्ट्रिंग समस्या को ठीक किया है। कैसे? एक सदिश के साथ इसे बदलकर, संकलन, फिर स्ट्रिंग को फिर से बदलना। यह लगातार वहां दुर्घटनाग्रस्त हो रहा था, और यह तय है कि यह ... हालांकि नहीं कर सका। वहाँ कुछ बुरा है, और मुझे यकीन नहीं है कि क्या।

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

3

कुछ स्थानों शुरू करने के लिए:

आप विंडोज पर हैं, तो और दृश्य सी ++ 6 (मैं भगवान कोई नहीं अभी भी इन दिनों इसे इस्तेमाल करता है की उम्मीद है) यह एसटीडी की implentation का उपयोग :: स्ट्रिंग threadsafe नहीं है, और इस तरह की चीज का कारण बन सकता है।

Here's an article I found which explains a lot of the common causes of memory leaks and corruption.

मेरे पिछले कार्यस्थल हम Compuware Boundschecker इस्तेमाल किया इस के साथ मदद करने के लिए। यह वाणिज्यिक और बहुत महंगा है, इसलिए यह विकल्प नहीं हो सकता है।

यहाँ जो कुछ काम का हो सकता है

http://www.codeguru.com/cpp/misc/misc/memory/article.php/c3745/

http://www.codeproject.com/KB/cpp/MemLeakDetect.aspx

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

1

शुद्ध करें चलाएं।

यह एक लगभग जादुई उपकरण है जो रिपोर्ट करेंगे जब आप स्मृति आप छू नहीं होना चाहिए clobbering कर रहे हैं, बातें, डबल-मुक्त, आदि को मुक्त नहीं द्वारा स्मृति लीक है

यह मशीन कोड के स्तर पर काम करता है , इसलिए आपके पास स्रोत कोड भी नहीं है।

सबसे मज़ेदार विक्रेता सम्मेलन कॉलों में से एक मैं तब था जब Purify को उनके कोड में एक स्मृति रिसाव मिली, और हम पूछने में सक्षम थे, "क्या यह संभव है कि आप अपने फ़ंक्शन में स्मृति को मुक्त नहीं कर रहे हैं foo() "और उनकी आवाज़ में आश्चर्य सुनें।

उन्होंने सोचा कि हम देवताओं को डीबग कर रहे थे लेकिन फिर हमने उन्हें गुप्त में जाने दिया ताकि वे अपने कोड का उपयोग करने से पहले शुद्धीकरण चला सकें। :-)

http://www-306.ibm.com/software/awdtools/purify/unix/

(यह बहुत महंगा है, लेकिन वे एक नि: शुल्क eval डाउनलोड किया है)

1

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

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

ध्यान दें कि यदि आपका प्रोग्राम बहुप्रचारित है, तो आपको शायद बड़ी समस्याएं हो सकती हैं। यदि नहीं, तो आप इसे इस तरह से कम करने में सक्षम होना चाहिए। सौभाग्य!

1

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

मेमोरी भ्रष्टाचार समस्या निवारण के लिए सबसे कठिन चीजों में से एक है और आमतौर पर इन प्रकार की समस्याओं को डीबगर में घंटे/दिन खर्च करके हल किया जाता है और "हे, पॉइंटर एक्स को हटा दिए जाने के बाद इसका उपयोग किया जा रहा है!"।

यदि यह किसी की सहायता करता है, तो यह अनुभव होता है जब आप अनुभव प्राप्त करते हैं।

सरणी के लिए आपकी स्मृति आवंटन सही दिखता है, लेकिन सुनिश्चित करें कि आप उन सभी स्थानों की जांच करें जहां आप सरणी तक पहुंचते हैं।

10

हम एक बार एक बग था जो सभी नियमित तकनीकों, वालग्रिंड, शुद्ध करने आदि को हटा देता था। दुर्घटना केवल मशीनों पर बहुत सारी स्मृति और केवल बड़े इनपुट डेटा सेट पर होती है।

आखिरकार हमने डीबगर घड़ी बिंदुओं का उपयोग करके इसे ट्रैक किया। मैं यहां प्रक्रिया का वर्णन करने की कोशिश करूंगा:

1) विफलता का कारण खोजें। यह आपके उदाहरण कोड से दिखता है, कि "exampleString" के लिए स्मृति दूषित हो रही है, और इसलिए इसे लिखा नहीं जा सकता है। आइए इस धारणा के साथ जारी रखें।

2) अंतिम ज्ञात स्थान पर एक ब्रेकपॉइंट सेट करें जो "exampleString" का उपयोग किसी भी समस्या के बिना किया जाता है या संशोधित किया जाता है।

3) 'exampleString' के डेटा सदस्य को एक घड़ी बिंदु जोड़ें। जी ++ के मेरे संस्करण के साथ, स्ट्रिंग _M_dataplus._M_p में संग्रहीत है। हम जानना चाहते हैं कि यह डेटा सदस्य कब बदलता है। इस के लिए GDB तकनीक है:

(gdb) p &exampleString._M_dataplus._M_p 
$3 = (char **) 0xbfccc2d8 
(gdb) watch *$3 
Hardware watchpoint 1: *$3 

मैं स्पष्ट रूप से जी के साथ लिनक्स का उपयोग कर रहा ++ और यहाँ GDB, लेकिन मेरा मानना ​​है कि स्मृति घड़ी अंक सबसे डिबगर के साथ उपलब्ध हैं कि।

4) जारी रखें जब तक घड़ी बिंदु शुरू हो रहा है:

Continuing. 
Hardware watchpoint 2: *$3 

Old value = 0xb7ec2604 "" 
New value = 0x804a014 "" 
0xb7e70a1c in std::string::_M_mutate() from /usr/lib/libstdc++.so.6 
(gdb) where 

gdb where आदेश एक पीठ दिखा क्या संशोधन के परिणामस्वरूप ट्रेस दे देंगे। यह या तो पूरी तरह से कानूनी संशोधन है, इस मामले में अभी जारी है - या यदि आप भाग्यशाली हैं तो यह स्मृति भ्रष्टाचार के कारण संशोधन होगा। बाद के मामले में, अब आपको उस कोड की समीक्षा करने में सक्षम होना चाहिए जो है समस्या उत्पन्न करने और उम्मीद है कि इसे ठीक करें।

हमारे बग का कारण नकारात्मक सूचकांक के साथ एक सरणी पहुंच था। सूचकांक एक 'int' modulos सरणी के आकार के लिए सूचक के एक कलाकार का परिणाम था। बग वाल्ग्रिंड एट अल द्वारा याद किया गया था। क्योंकि उन उपकरणों के तहत चलने पर आवंटित स्मृति पते कभी भी "> MAX_INT" नहीं था और इसलिए कभी नकारात्मक सूचकांक नहीं हुआ।

+0

ग्रेट चर्चा! मिस उस पर्यावरण में विकासशील है। WinDoze के लिए एक समाधान की आवश्यकता है ... (वीएस 6.0 भी) ... (मेरी गलती नहीं! ग्राहक वीएस 6.0 और ग्राहकों का हमेशा सही उपयोग करते हैं :)। –