2009-03-04 22 views
8
//creates memory leak 
    self.editMyObject = [[MyObject alloc] init]; 

//does not create memory leak 
    MyObject *temp = [[MyObject alloc] init]; 
    self.editMyObject = temp; 
    [temp release]; 

कोड की पहली पंक्ति मेमोरी रिसाव बनाती है, भले ही आप कक्षा के डेलोक विधि में [self.editMyObject रिलीज] करते हैं। self.editMyObject MyObject प्रकार का है। दूसरी पंक्ति में कोई स्मृति रिसाव नहीं है। क्या पहली पंक्ति सिर्फ गलत है या क्या स्मृति को मुक्त करने का कोई तरीका है?यह मेमोरी लीक (आईफोन) क्यों बनाता है?

+0

तीन अच्छे उत्तरों। ध्यान दें कि उत्तर देने के लिए भी कौन है। – 4thSpace

उत्तर

10

सही व्यवहार संपादन MyObject @property की घोषणा पर निर्भर करता है। मान लें यह

@property (retain) id editMyObject; //id may be replaced by a more specific type 

या

@property (copy) id editMyObject; 

तो self.editMyObject = के माध्यम से काम को बरकरार रखे हुए या प्रतियां सौंपा वस्तु के रूप में delcared है। चूंकि [[MyObject alloc] init] एक बनाए गए ऑब्जेक्ट को लौटाता है, जिसे आप कॉलर के रूप में रखते हैं, तो आपके पास MyObject इंस्टेंस का अतिरिक्त बरकरार रहता है और इसलिए यह तब तक रिसाव हो जाएगा जब तक कि यह मेल खाने वाली रिलीज़ न हो (जैसे दूसरे ब्लॉक में)। मैं सुझाव दूंगा कि आप Memory Management Programming Guide [2] पढ़ लें।

आपका दूसरा कोड ब्लॉक सही है, मान लीजिए कि ऊपर वर्णित संपत्ति घोषित की गई है।

पेज। -dealloc विधि में आपको [self.editMyObject release] का उपयोग नहीं करना चाहिए। आपको [editMyObject release] पर कॉल करना चाहिए (माना जाता है कि ivar बैकिंग @property को editMyObject कहा जाता है)। एक्सेसर को कॉल करना (self.editMyObject के माध्यम से @ सिंथेसाइज्ड एक्सेसर्स के लिए सुरक्षित है, लेकिन यदि ओवरराइडन एक्सेसर ऑब्जेक्ट स्टेटस पर निर्भर करता है (जो -dealloc में कॉलिंग स्थान पर मान्य नहीं हो सकता है या अन्य दुष्प्रभावों का कारण बनता है, तो आपके पास एक्सेसर को कॉल करके एक बग है।

[2] कोको में वस्तु स्वामित्व नियम बहुत सरल है: यदि आप एक विधि है कि alloc, या अपने हस्ताक्षर में copy फोन (या +[NSObject new] जो मूल रूप से [[NSObject alloc] init] के बराबर है का उपयोग करें), तो आप "स्वयं" उद्देश्य यह है कि वापस कर दिया गया है और आपको release के साथ स्वामित्व के अधिग्रहण को संतुलित करना होगा। अन्य सभी मामलों में, आपके पास किसी विधि से लौटाई गई वस्तु का स्वामित्व नहीं है। अगर आप इसे रखना चाहते हैं, तो आपको retain के साथ स्वामित्व लेना होगा, और बाद में स्वामित्व जारी करना होगा release के साथ।

+0

मेरे पास एक एनएसएमयूटेबलएरे है। मैंने इसे प्रतिलिपि बनाने के लिए सेट किया है, लेकिन जब मैं ऐसा करता हूं [self.List addObject: myobject], मुझे एक अपवाद अपवाद मिलता है। ठीक काम करने के लिए इसे वापस सेट करना। कोई सुझाव? – 4thSpace

+0

मेरा मानना ​​है कि एक @property (प्रतिलिपि) कॉपी बनाने के लिए -पीपी का उपयोग करेगा, भले ही नया असाइनमेंट एक उत्परिवर्तनीय प्रकार हो।इस प्रकार आप एक अपरिवर्तनीय प्रति प्राप्त करते हैं (आप आम तौर पर एक म्यूटेबल प्रतिलिपि बनाने के लिए mutableCopy का उपयोग करेंगे), जब आप असाइन किए गए मान को म्यूट करने का प्रयास करते हैं तो अपवाद उत्पन्न होता है .... –

+0

[cont'd] आप @property (बनाए रखना) का उपयोग कर सकते हैं और स्वयं की तरह असाइन करें। सूची = [[mutableArr mutableCopy] autorelease]। –

8

आपकी संपत्ति "बनाए रखने" घोषित की गई है जिसका अर्थ यह है कि यह पारित वस्तु स्वचालित रूप से बरकरार रखी जाती है।

क्योंकि आपके ऑब्जेक्ट में पहले से ही एक आवंटन/इनिट से संदर्भ गणना थी, तो दो संदर्भ हैं और मैं केवल एक रिलीज (आपके विनाशक में) मान रहा हूं।

असल में self.editMyObject को कॉल वास्तव में यह कर रहा है;

-(void) setEditMyObject:(MyObject*)obj 
{ 
    if (editMyObject) 
    { 
    [editMyObject release]; 
    editMyObject = nil; 
    } 

    editMyObject = [obj retain]; 
} 
+0

सिवाय इसके कि यदि 'editMyObject == obj'' है, तो यह बहुत असफल हो सकता है, क्योंकि आप ऑब्जेक्ट को जारी कर रहे हैं (संभावित रूप से इसे नष्ट कर रहे हैं), और उसके बाद एक डिलीओटेड पॉइंटर को बनाए रखने का प्रयास कर रहे हैं। –

3

पहला संस्करण मेल खाने वाली रिलीज के बिना ऑब्जेक्ट बनाता है। जब आप ऑब्जेक्ट आवंटित करते हैं, तो इसका मतलब है कि आप उस ऑब्जेक्ट के स्वामी हैं। आपका सेटर संभवतः ऑब्जेक्ट को बनाए रखता है (जैसा कि यह होना चाहिए), जिसका अर्थ है कि अब आप ऑब्जेक्ट को दो बार मालिक हैं। ऑब्जेक्ट सृजन को संतुलित करने के लिए आपको रिलीज़ की आवश्यकता है।

यदि आप कोको का उपयोग करने की योजना बना रहे हैं तो आपको the Cocoa memory management guide पढ़ना चाहिए। एक बार सीखने के बाद यह मुश्किल नहीं है, लेकिन यह कुछ है जो आपको सीखना है या आपको इस तरह की कई समस्याएं मिलेंगी।

1

बाकी सब पहले से ही कवर किया है कारण है कि यह एक स्मृति रिसाव का कारण बनता है, तो मैं बस कैसे 'अस्थायी' चर से बचने के लिए के साथ झंकार और अभी भी रोक देंगे एक स्मृति रिसाव:

self.editMyObject = [[[MyObject alloc] init] autorelease]; 

यह छोड़ देंगे अपने (बनाए रखें) संपत्ति को नई वस्तु के एकमात्र मालिक के रूप में रखें। वास्तव में आपके दूसरे उदाहरण के समान परिणाम, लेकिन अस्थायी वस्तु के बिना।

+0

डेस्कटॉप ऐप में, मैं आमतौर पर ऐसा करता हूं। हालांकि, आईफोन (या किसी मेमोरी बाधित वातावरण) पर, ऑटोरेलीज का उपयोग करके स्मृति उपयोग अनावश्यक रूप से बढ़ सकता है। जब तक आपको ऑटोरेलीज की आवश्यकता न हो तब तक बनाए रखें/रिलीज़ के साथ चिपकाएं। –

+0

हम्म। मैं निश्चित रूप से इस पर डेस्कटॉप पक्ष से आ रहा हूँ। क्या आप समझ सकते हैं कि स्पाइक का कारण क्या है? ऐसा लगता है कि इस मामले में कोई अतिरिक्त मेमोरी आवंटित नहीं की गई है, लेकिन मेरा आईफोन कोडिंग अनुभव सीमित है। –

+0

मुझे विवरण नहीं पता लेकिन यह अच्छी तरह से प्रलेखित है कि ऑटोरेलीज आईफोन पर काफी महंगा कॉल है। – 4thSpace

4

कोको और कोको-टच में सम्मेलन द्वारा, [[SomeClass alloc] initX] या [SomeClass newX] का उपयोग करके बनाई गई कोई भी वस्तु एक की एक सतत गणना के साथ बनाई गई है। जब आप अपने नए उदाहरण के साथ होते हैं, तो आमतौर पर विधि में [someClassInstance release] पर कॉल करने के लिए आप ज़िम्मेदार हैं।

जहां इस मुश्किल हो जाता है जब आप एक संपत्ति के बजाय का एक उदाहरण चर के लिए अपने नए वस्तु सौंपते हैं। अधिकांश गुणों को retain या copy के रूप में परिभाषित किया गया है, जिसका अर्थ है कि वे सेट करते समय ऑब्जेक्ट की बनाए रखने की गिनती को बढ़ाते हैं, या ऑब्जेक्ट की एक प्रति बनाते हैं, जिससे मूल छूटे हुए होते हैं।

अपने उदाहरण में, आप शायद अपनी .h फ़ाइल में इस है:

@property (retain) MyObject *editMyObject; 
अपने पहले उदाहरण में

तो:

// (2) property setter increments retain count to 2 
self.editMyObject = 

    // (1) new object created with retain count of 1 
    [[MyObject alloc] init]; 

// oops! retain count is now 2 

आप alloc/init का उपयोग कर MyObject के अपने नए उदाहरण बनाते हैं, यह एक की गिनती गिनती है। जब आप self.editMyObject को नया उदाहरण असाइन करते हैं, तो आप वास्तव में -setEditMyObject: विधि है कि संकलक जब आप @synthesize editMyObject के लिए बनाता है कॉल कर रहे हैं। जब संकलक self.editMyObject = x देखता है, तो यह [self setEditMyObject: x] के साथ बदल देता है।

अपने दूसरे उदाहरण में:

MyObject *temp = [[MyObject alloc] init]; 
// (1) new object created with retain count of 1 

self.editMyObject = temp; 
// (2) equivalent to [self setEditMyObject: temp]; 
// increments retain count to 2 

[temp release]; 
// (3) decrements retain count to 1 

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

भी देखें Cocoa strategy for pointer/memory management

0

इस बात पर सहमति और बताया कि नीचे कोड रिसाव (@property को बनाए रखने और editMyObject के लिए @synthesize कल्पना करते हुए) नहीं है किया गया था:

//does not create memory leak 
MyObject *temp = [[MyObject alloc] init]; 
self.editMyObject = tempt; 
[temp release]; 

प्रश्न: कुछ गलत है निम्न कोड के साथ जो एक temp सूचक का उपयोग नहीं करता है?

//does not create memory leak ? 
self.editMyObject = [[MyObject alloc] init]; 
[editMyObject release]; 

मेरे लिए यह ठीक दिखता है।

+0

आपको ऑब्जेक्ट को जारी करने के लिए आपके डेलोक विधि में यह सुनिश्चित करने की आवश्यकता है: [संपादित करें MyObject रिलीज] या self.editMyObject = शून्य; – jyavenard

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