6

पर रिलीज को कैसे बल दें मैं एआरसी के लिए नया हूं लेकिन समझता हूं कि यह कैसे काम करता है और मैं इसे आजमा रहा हूं। मैं आईओएस पर हूं इसलिए स्मृति एक गंभीर चिंता है।आईओएस

मेरे पास एक MyObject क्लास है जिसमें बहुत से बड़े डेटा हैं। मैं इसे छोड़ना चाहता हूं, और डेटा का एक नया सेट लोड करना चाहता हूं।

MyObject *object; 
object = [[MyObject alloc] initWithData:folder1]; // load data from folder1 

// later... 
object = [[MyObject alloc] initWithData:folder2]; // load data from folder2 

इस लीक के बिना ठीक काम करता है, और मैं एआरसी अनुमान लगा रहा हूँ नया असाइनमेंट से पहले एक [वस्तु रिहाई] सम्मिलित करता है। मेरी समस्या यह है कि 'ऑब्जेक्ट' के अंदर डेटा के बाद जारी किया गया है, नया सेट आवंटित किया गया है, और मैं स्मृति से बाहर हूं। मैं वास्तव में क्या करने में सक्षम होना चाहता हूं:

object = nil; 

<function to pop the pool, wait till everything is deallocated> 

object = [MyObject alloc] initWithData:folder2]; // load data from folder2 

लेकिन मुझे यकीन नहीं है कि यह कैसे करें। मैं बाद में एक प्रदर्शन चयनकर्ता पर नया आवंटन चला सकता हूं, लेकिन ऐसा लगता है जैसे मैं अंधेरे में शूटिंग कर रहा हूं और कुछ हैक। ऐसा करने के लिए शायद उचित तरीका है?

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

अद्यतन
जवाब के लिए धन्यवाद, मैं पहले से ही

object = nil; 
object = [MyObject alloc] initWithData:folder2]; 

की कोशिश की होगी और यह काम नहीं किया था। मुझे यकीन नहीं था कि यह माना जाता था या नहीं। अब मैं समझता हूं कि यह काम करना चाहिए, लेकिन मेरे पास एक सेकंड के उस अंश के लिए कुछ और होनी चाहिए। मेरे पास अपने सभी init/dealloc विधियों में एनएसएलॉग हैं, और मैं पहले कक्षाओं (माइओब्जेक्ट के इवर्स) के नए उदाहरणों के सभी अंतर्निहितों को देख सकता हूं, और फिर लगभग तुरंत (कुछ एमएस के भीतर), MyObject के dealloc , इसके बाद इसके इवर के deallocs। मैंने @autorelease भी कोशिश की लेकिन वही बात होती है।

मैंने पूरे प्रोजेक्ट की खोज की है और मुझे लगता है कि सभी कोड चिपकाए हैं जो मुझे लगता है कि इससे प्रासंगिक हो सकता है।

@interface AppDelegate : UIResponder <UIApplicationDelegate>; 
    @property PBSoundSession *soundSession; 
@end 


//-------------------------------------------------------------- 
@implementation AppDelegate 

// onTimer fired at 60Hz 
-(void)onTimer:(NSTimer *) theTimer { 
    [oscReceiver readIncoming]; // check incoming OSC messages 
    // then do a bunch of stuff with _soundSession; 
} 
@end 


//-------------------------------------------------------------- 
@implementation OscReceiver 

-(void)readIncoming { 
    AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate]; 

    // parse all incoming messages 

    if(bLoadNewSoundBank) { 
     NSString *newFolder = parseNewFolder(); 
     appDelegate.soundSession = nil; 
     appDelegate.soundSession = [MyObject alloc] initWithData:newFolder]; 
    } 
} 

@end 


//-------------------------------------------------------------- 
@implementation GuiController 

// onTimer fired at 10Hz 
-(void)onTimer:(NSTimer *) theTimer { 
    PBSoundSession *soundSession = appDelegate.soundSession; 
    // update gui with received values 
} 

@end 

मैंने सोचा कि यह GuiController :: OnTimer कि विधि की अवधि के लिए वर्ष appDelegate.soundSession पकड़े में 'soundSession' स्थानीय चर हो सकता है, लेकिन मेरे आश्चर्य जीयूआई कोड के सभी बाहर टिप्पणी (वास्तव में टाइमर को अक्षम करना), कोई फर्क नहीं पड़ता।

क्या उस बिंदु पर पता लगाने का कोई तरीका है जो अभी भी मेरे appDelegate.soundSession पर है? मैंने एक ब्रेकपॉइंट रखा जहां मैंने इसे शून्य पर सेट किया, लेकिन कोई उपयोगी जानकारी नहीं मिली। मैंने आवंटन टेम्पलेट में इंस्ट्रूमेंट्स की कोशिश की, लेकिन वहां कुछ भी उपयोगी नहीं मिला (शायद क्योंकि मुझे नहीं पता कि कहां देखना है)।

यह मेरा आवंटन ट्रैक जैसा दिखता है, आप देख सकते हैं कि स्मृति बहुत देर हो चुकी है! Valid XHTML

+0

ठीक है, आप नई ऑब्जेक्ट आवंटित/इनिट करने से पहले 'ऑब्जेक्ट = एनआईएल' कर कर जो कुछ भी चाहते हैं उसे प्राप्त करेंगे। –

उत्तर

10

यह एक एआरसी समस्या नहीं हो सकती है। आप जो देख सकते हैं वह आपके autorelease pool जल्द ही समाप्त नहीं हो रहा है-आपका मायऑब्जेक्ट जारी हो रहा है, लेकिन कुछ आंतरिक -retain/-autorelease जोड़ी के कारण यह लोड किया गया डेटा पूल द्वारा आयोजित किया जा रहा है।इस तरह की एक @autoreleasepool ब्लॉक में अपने -initWithData: कॉल लपेटकर कोशिश करें,:

@autoreleasepool { 
    object = [[MyObject alloc] initWithData:folder1]; 
    // do things 
} 
// later… 
@autoreleasepool { 
    object = [[MyObject alloc] initWitData:folder2]; 
    // do other things 
} 

तुरंत कुछ और करने के लिए सेट करने से पहले nil करने के लिए वस्तु की स्थापना गैब्रिएल पता चलता है के रूप में पहले दूसरे -alloc/-initWithData: उचित जारी डालने के लिए संकलक कारण हो सकता है , लेकिन यह पहले से ऐसा करने के लिए पर्याप्त स्मार्ट हो सकता है-अगर यह काम नहीं करता है, तो यह ऑटोरेलीज-पूल चीज़ की सबसे अधिक संभावना है।

+0

मैंने अपना जवाब संशोधित किया। सूचकांक को फिर से सौंपने से पहले यह निश्चित रूप से स्मृति ** जारी करता है, अन्यथा स्मृति स्मृति रिसाव तब होगा जब स्मृति के इस हिस्से का कोई संदर्भ नहीं होगा। –

+0

राइट-मैं कह रहा हूं कि यह संभव है कि पुन: असाइनमेंट से पहले ** ** ** यानी ''alloc'/'-initWithData:' के बाद, लेकिन 'ऑब्जेक्ट' के परिणामस्वरूप सेट होने से पहले, उस स्थिति में क्षण में स्मृति में दो MyObjects होगा। –

+0

अच्छा बिंदु, मुझे इसके बारे में सोचना है –

3

@autoreleasepool {...} को निकालने में कोई देरी नहीं है; पूल में ऑब्जेक्ट्स release तुरंत आवेदित हैं। यदि कोई ऑब्जेक्ट जीवित रहता है, तो ऐसा इसलिए होता है क्योंकि या तो strong संदर्भ कहीं और है या क्योंकि ऑब्जेक्ट autorelease डी अगले पूल आउट में था।

यदि आप करते हैं:

a = [[Foo alloc] initBigThing]; 
a = nil; 
a = [[Foo alloc] initBigThing]; 

Foo का पहला उदाहरण एक बड़ी चेतावनी के साथ दूसरे

के आवंटन से पहले जारी किया जाएगा; यदि a पर कोड कोडों में से कोई भी retain/autorelease पर होने पर लागू होता है, तो यह तब तक टिकेगा जब तक कि पूल निकाला न जाए। @autoreleasepool{ ... }; में इसके आस-पास की चाल चलनी चाहिए।

ध्यान दें कि संकलक कभी-कभी अनुकूलित किए गए निर्माण में समाप्त किए गए गैर-अनुकूलित बिल्डों में retain/autorelease अनुक्रमों को उत्सर्जित करेगा।

1

एक अधिक सामान्य जवाब थोड़ा, मैंने पाया है कि कैसे आप एक वस्तु को रिलीज के लिए मजबूर कर सकते हैं:

#import <objc/message.h> 

// --- 

while ([[object valueForKey:@"retainCount"] integerValue] > 1) { 
    objc_msgSend(object, NSSelectorFromString(@"release")); 
} 
objc_msgSend(object, NSSelectorFromString(@"release")); 

लेकिन यदि आप ऐसा नहीं करना चाहिए, क्योंकि एआरसी शायद वस्तु बाद में जारी करेंगे और यह एक दुर्घटना का कारण होगा। इस विधि का उपयोग केवल डीबग में किया जाना चाहिए!