2013-01-10 8 views
6

प्रस्तावना; यह एक सामान्य नहीं है "मेरे पास एक रिसाव के साथ एक विशाल ऐप है" प्रश्न। यह स्वचालित संदर्भ गणना के बारे में एक विशिष्ट मुद्दा है जो पूर्ण स्रोत कोड, या सूक्ष्म कोड जनरेशन या कंपाइलर समस्या, या उपकरण में एक बग के साथ लगभग मामूली डेमो ऐप में ठीक से काम नहीं कर रहा है। (टीएलडीआर: ओह। असल में एक अजीब छोटी दौड़ की स्थिति)एक्सकोड 4.5 में एआरसी के साथ एक प्रेत मेमोरी लीक जहां डेलोक को निश्चित रूप से बुलाया जाता है या एक इंस्ट्रूमेंट्स मुद्दा होता है?

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

रखरखाव काउंट कभी नहीं बढ़ता है 1. इसे किसी के द्वारा बनाए रखा नहीं जा रहा है, और इसे हटा दिया जा रहा है, और फिर भी ऐसा लगता है कि यह एक "रिसाव" है क्योंकि यह इंस्ट्रूमेंट के लीक में एक सक्रिय उदाहरण के रूप में दिखाता है।

यह कैसे संभव है?

मैं अभी भी एआरसी के साथ उद्देश्य-सी सीख रहा हूं, और इसलिए मुझे लगता है कि मुझे एक आम शुरुआत करने वाली गलती करनी होगी। यहाँ मेरी केवल init है और मेरी वस्तु की dealloc:

- (id) initWithMessage:(NSString*)messageForUser 
{ 
    self = [super init]; 
    if (self) 
    { 
     _message = messageForUser; 
     NSLog(@"from constructor: %@",_message); 
    } 
    return self; 

} 

- (void)dealloc { 
    NSLog(@"Goodbye cruel world. One WPMyObject signing off."); 
    // [message release]; // ARC forbiddeth thee! Begone release. 
    _message = nil; 

    // [super dealloc]; // ARC forbiddeth explicit super dealloc 
} 

बस अगर मैं कर सकता देखने के लिए, मैं dealloc विधि में [super dealloc] कॉल करने की कोशिश, और एआरसी एक त्रुटि है, जो बहुत अच्छा है के साथ ब्लॉक क्योंकि यह करने के लिए जा रहा है वह आप के लिए है। हालांकि जब मैं अपनी खुद की init विधि लिखता हूं, यह मुझे अवरुद्ध नहीं करता है।

जब मैं एक्सकोड में "रन" का उपयोग कर प्रोग्राम चलाता हूं, तो मुझे "अलविदा क्रूर दुनिया" एनएसएलओजी संदेश मिलता है, जैसा कि मैंने आशा की थी कि जब मैं डेलोक चलाऊंगा, तब भी मुझे यह सबूत मिलेंगे कि उदाहरण अभी भी मौजूद है रन के अंत में, जब मेमोरी लीक टेम्पलेट का उपयोग करके इंस्ट्रूमेंट्स विश्लेषण का उपयोग किया जाता है:

यदि मैं नीचे दिए गए इंस्टेंस सृजन कोड के बिना चलाता हूं, तो मुझे केवल कुछ मानक लाइब्रेरी मॉलोक लीक की सूचना मिलती है, लेकिन अगर मैं यह कोड जोड़ता हूं, तो सभी लीक होते हैं:

WPMyObject * myObject = [[WPMyObject alloc] initWithMessage: @"Hello World!\n" ]; 

यहाँ मैं क्या दिखाई दे रही है है, और लगता है कि मैं समझता हूँ कि मुझे उस WPMyObject का एकमात्र उदाहरण लीक कर रहा है कह रहा है:

enter image description here

पूर्ण स्रोत कोड जो काफी तुच्छ है (एक छोटे से मैक ओएस एक्स कमांड लाइन एप्लिकेशन का उपयोग करने ऑब्जेक्टिव-सी और Foundation/Foundation.h) BitBucket पर है। अपने ब्राउज़र में स्रोत कोड देखने के लिए this link पर क्लिक करें।

main.m इकाई, एक एकल परीक्षण वस्तु दृष्टान्त निर्माण चलाता है एक @autoreleasepool {...} संदर्भ बयान के अंदर:

enter image description here

आप अपने कंप्यूटर पर पूरी तरह से तुच्छ कोड देख इस तरह यह हड़पने के लिए चाहते हैं :

hg clone https://bitbucket.org/wpostma/objectivecplaymac 

अद्यतन: आप (जो उपकरण में एक बग, या एक बजना/LLVM संकलक बग, और नहीं एक "वास्तविक रिसाव" हो सकता है) "रिसाव" बस से पहले कोड की इस पंक्ति जोड़कर ठीक कर सकते हैं } जो ऑटोरेलीज पूल समाप्त होता है:

NSLog(@"Reached end of autorelease pool"); 

हाँ। लॉग संदेश जोड़ें। "लीक" चला जाता है।यह मैक ओएस एक्स 10.7.5 पर एक्सकोड 4.5.2 (4 जी 2008 ए) है, जिसमें इंस्ट्रूमेंट्स संस्करण 4.5 (4523 बिल्ड) शामिल है।

अद्यतन 2: यह वास्तव में एक साधारण बहु-प्रक्रिया दौड़ स्थिति है। नीचे दिया गया कोड हैकरी का उचित डीबग-बिल्ड बिट प्रतीत होता है। अगर कहने का एक और स्पष्ट तरीका था "जब तक उपकरण मेरे साथ नहीं किया जाता है तब तक प्रतीक्षा करें, और फिर मुख्य() से बाहर निकलें", यह एक अच्छी भविष्य की सुविधा हो सकती है, ऐप्पल इंजीनियरों। एक PROFILER_SYNC ("संदेश") मैक्रो जो रिहाई मोड में कुछ भी नहीं फैलता है, लेकिन डीबग बिल्ड में, प्रोफाइलर को "संदेश" भेजता है .... यह वास्तव में बहुत आसान हो सकता है।

int main(int argc, const char * argv[]) 
{ 
    // This creates and cleans up an auto-release pool context. 
    @autoreleasepool { 

     foo(); // Microscopic amounts of debug code you want profiler to analyze go here. 

#ifdef DEBUG 
     usleep(10000); // race condition prevention in debug builds, so Instruments can finish up. 
#endif 

    } 
#ifdef DEBUG 
    usleep(10000); // race condition prevention in debug builds, so Instruments can finish up. 
#endif 

    return 0; 
} 

उत्तर

3

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

ऑटोरेलीज पूल पर बंद ब्रेस के बाद sleep(100); डालने का प्रयास करें। या dealloc में लॉग संदेश में एक गुच्छा अधिक टेक्स्ट जोड़ने का प्रयास करें।

यदि यह "ठीक" नहीं होता है, तो डिस्सेप्लर दिखाएं और देखें कि कोड के दो संस्करणों के बीच क्या परिवर्तन है।


ऐसा क्यों होता है: दोनों इंस्ट्रूमेंट्स और एनएसएलओजी() प्रदर्शन कारणों से प्रभावी ढंग से बफर किए जाते हैं। वे अपेक्षाकृत लंबी चल रही प्रक्रिया में उपयोग के लिए डिज़ाइन किए गए हैं जो लगभग हमेशा मुख्य घटना लूप या dispatch_main() पर कॉल करते हैं।

यह लक्ष्य अनुप्रयोग के प्रदर्शन को कम करने और कम से कम प्रभावित करने के लिए किया जाता है, लेकिन यह माइक्रो बेंचमार्क में अजीबता का कारण बन सकता है जहां प्रक्रिया बेहद कम रहती है।

यदि आपके पास अल्पकालिक प्रक्रिया में न्यूनतम परीक्षण केस है, तो मैं main() को [[NSRunLoop currentLoop] run]; के साथ बंद करने की अनुशंसा करता हूं। वह हमेशा के लिए चलेगा और आपको इंस्ट्रूमेंट्स और/या डीबगर के लिए एक व्यवहार्य रनटाइम देगा।

+0

उपकरण के ढेर-देखने-धागे, और मेरे कार्यक्रम का मुख्य धागा, मूल रूप से एक दौड़ की स्थिति? क्योंकि यह केवल दो धागे/प्रक्रियाओं में शामिल है, मैं कल्पना कर सकता हूं कि इसमें शामिल होने के कारण, मैंने कोई अतिरिक्त उपयोगकर्ता-थ्रेड नहीं बनाया है ... क्या अजीब बात यह है कि एनएसएलओजी इसे ठीक करता है लेकिन सीएफशो (सीएफएसआरटी ("कुछ") को कॉल नहीं करता है) जिसका मतलब है कि यदि यह दौड़ की स्थिति है, तो एनएसएलओजी सीएफशो से बहुत धीमी है। :-) –

+0

नींद (100) (100 सेकंड) बस थोड़ा अधिक हो सकता है। :-) दो जगहों पर 100 एमसीसी के लिए सोने के लिए बदल गया, जहां मुझे लगता है कि उपकरण को कार्रवाई के साथ पकड़ने के लिए कुछ समय लग सकता है। इसे डबल करें और ग़लत एक जोड़ें, अगर आपको पसंद है, प्रिय भविष्य के पाठक। –

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