2014-07-25 6 views
7

मैं इसNSThread स्वचालित रूप से अब autoreleasepool पैदा करता है?

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil]; 
    [thread start]; 
} 

-(void)test 
{ 
    MyClass *my = [[[MyClass alloc] init] autorelease]; 
    NSLog(@"%@",[my description]); 
} 

मैं अपने खुद के धागे के लिए किसी भी autoreleasepool का निर्माण नहीं किया की तरह परीक्षण कोड है, लेकिन जब धागा बाहर निकलें, वस्तु "मेरे" बस dealloc.why?

भले ही मैं नीचे

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil]; 
    [thread start]; 
} 

-(void)test 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    MyClass *my = [[[MyClass alloc] init] autorelease]; 
    NSLog(@"%@",[my description]); 
} 

मैं अपने खुद के autoreleasepool बनाने के रूप में अपने परीक्षण कोड बदलने लेकिन यह नाली नहीं जब धागा बाहर निकलें। वस्तु "मेरा" अभी भी वैसे भी dealloc कर सकते हैं। क्यूं कर?

मैं Xcode5 और एआरसी

+0

आप कैसे कह रहे हैं कि मेरा ऑब्जेक्ट रिलीज़ हो गया है? –

+0

क्या आप आवश्यक जानकारी प्राप्त करने में सक्षम हैं? –

+0

क्योंकि मेरे पास "my" की dealloc विधि – eliudnis

उत्तर

1

Apple documentation says (4 वें पैरा) का उपयोग नहीं का उपयोग करें:

आप सामान्य alloc और init संदेश के साथ एक NSAutoreleasePool वस्तु बना सकते हैं और (नाली के साथ इसे के निपटान या जारी करने के अंतर को समझने, कचरा संग्रहण देखें)। चूंकि आप एक autorelease पूल बनाए रखने नहीं कर सकते हैं (या autorelease यह देखने को बनाए रखने और autorelease), draining एक पूल अंततः यह deallocating का प्रभाव पड़ता है। आप हमेशा (एक विधि या क्रिया, या एक पाश के शरीर के आह्वान) उसी संदर्भ में एक autorelease पूल नाली चाहिए कि यह बनाया गया था। अधिक जानकारी के लिए Autorelease पूल ब्लॉक का उपयोग देखें।

16

यह दर्ज नहीं किया है, लेकिन इस सवाल का जवाब हाँ हो सकता है, पर ओएस एक्स 10.9+ और iOS 7+ प्रकट होता है।

ऑब्जेक्टिव-सी क्रम open-source ताकि आप को देखने के लिए क्या हो रहा है स्रोत पढ़ सकते है। क्रम (646 है, जो ओएस एक्स 10.10 और iOS 8 के साथ भेज दिया) यदि आप वर्तमान धागे पर एक पूल के बिना एक autorelease प्रदर्शन वास्तव में एक पूल जोड़ता है का नवीनतम संस्करण। NSObject.mm में:

static __attribute__((noinline)) 
id *autoreleaseNoPage(id obj) 
{ 
    // No pool in place. 
    assert(!hotPage()); 

    if (obj != POOL_SENTINEL && DebugMissingPools) { 
     // We are pushing an object with no pool in place, 
     // and no-pool debugging was requested by environment. 
     _objc_inform("MISSING POOLS: Object %p of class %s " 
        "autoreleased with no pool in place - " 
        "just leaking - break on " 
        "objc_autoreleaseNoPool() to debug", 
        (void*)obj, object_getClassName(obj)); 
     objc_autoreleaseNoPool(obj); 
     return nil; 
    } 

    // Install the first page. 
    AutoreleasePoolPage *page = new AutoreleasePoolPage(nil); 
    setHotPage(page); 

    // Push an autorelease pool boundary if it wasn't already requested. 
    if (obj != POOL_SENTINEL) { 
     page->add(POOL_SENTINEL); 
    } 

    // Push the requested object. 
    return page->add(obj); 
} 

इस समारोह कहा जाता है जब आप पहली बार पूल धक्का (इस स्थिति में बात धक्का दिया POOL_SENTINEL है), या आप कोई पूल के साथ autorelease। जब पहला पूल धक्का दिया जाता है, तो यह ऑटोरेलीज़ स्टैक सेट करता है। लेकिन जैसा कि आप कोड से देखते हैं, जब तक DebugMissingPools पर्यावरणीय चर सेट नहीं होता है (यह डिफ़ॉल्ट रूप से सेट नहीं होता है), जब कोई पूल के साथ ऑटोरेलीज नहीं किया जाता है, तो यह ऑटोरेलीज़ स्टैक भी सेट करता है, और फिर पूल को धक्का देता है (एक धक्का देता है POOL_SENTINEL)।

इसी प्रकार, (अन्य कोड को देखे बिना पालन करना थोड़ा मुश्किल है, लेकिन यह प्रासंगिक हिस्सा है) जब थ्रेड नष्ट हो जाता है (और थ्रेड-लोकल स्टोरेज नष्ट हो जाता है), यह ऑटोरेलीज स्टैक में सबकुछ जारी करता है (कि क्या pop(0); करता है) तो यह पिछले पूल पॉप उपयोगकर्ता पर निर्भर नहीं करता:

static void tls_dealloc(void *p) 
{ 
    // reinstate TLS value while we work 
    setHotPage((AutoreleasePoolPage *)p); 
    pop(0); 
    setHotPage(nil); 
} 

क्रम (551.1, जो ओएस के साथ आया था एक्स 10.9 और iOS 7) के पिछले संस्करण, भी ऐसा किया, जैसा कि आप अपने NSObject.mm:

static __attribute__((noinline)) 
id *autoreleaseSlow(id obj) 
{ 
    AutoreleasePoolPage *page; 
    page = hotPage(); 

    // The code below assumes some cases are handled by autoreleaseFast() 
    assert(!page || page->full()); 

    if (!page) { 
     // No pool. Silently push one. 
     assert(obj != POOL_SENTINEL); 

     if (DebugMissingPools) { 
      _objc_inform("MISSING POOLS: Object %p of class %s " 
         "autoreleased with no pool in place - " 
         "just leaking - break on " 
         "objc_autoreleaseNoPool() to debug", 
         (void*)obj, object_getClassName(obj)); 
      objc_autoreleaseNoPool(obj); 
      return nil; 
     } 

     push(); 
     page = hotPage(); 
    } 

    do { 
     if (page->child) page = page->child; 
     else page = new AutoreleasePoolPage(page); 
    } while (page->full()); 

    setHotPage(page); 
    return page->add(obj); 
} 
से देख सकते हैं

लेकिन इससे पहले संस्करण (532.2, जो ओएस एक्स 10 के साथ आया था।8 और iOS 6), does not:

static __attribute__((noinline)) 
id *autoreleaseSlow(id obj) 
{ 
    AutoreleasePoolPage *page; 
    page = hotPage(); 

    // The code below assumes some cases are handled by autoreleaseFast() 
    assert(!page || page->full()); 

    if (!page) { 
     assert(obj != POOL_SENTINEL); 
     _objc_inform("Object %p of class %s autoreleased " 
        "with no pool in place - just leaking - " 
        "break on objc_autoreleaseNoPool() to debug", 
        obj, object_getClassName(obj)); 
     objc_autoreleaseNoPool(obj); 
     return NULL; 
    } 

    do { 
     if (page->child) page = page->child; 
     else page = new AutoreleasePoolPage(page); 
    } while (page->full()); 

    setHotPage(page); 
    return page->add(obj); 
} 

ध्यान दें कि किसी भी pthread रों के लिए ऊपर काम करता है, न सिर्फ NSThread रों।

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

+0

ऑब्जेक्ट में ब्रेकपॉइंट है। महान जासूस काम। पोस्ट करने का शुक्रिया। (वोट दिया गया) –

+1

ध्यान दें कि स्वचालित थ्रेड के लिए स्वचालित सफाई * नहीं * होती है। क्लीनअप फ़ंक्शन 'tls_dealloc' एक थ्रेड-लोकल-स्टोरेज (टीएलएस) विनाशक है, जिसे' pthread_key_init_np' पर कॉल द्वारा जोड़ा गया है। इन विनाशकों को 'pthread_exit' से बुलाया जाता है, जो थ्रेड को प्रारंभिक रूप से बुलाया जाता है जब एक थ्रेड अपनी प्रारंभिक दिनचर्या से वापस आता है, लेकिन मुख्य धागे के मामले में नहीं। तो 'autoreleaseNoPage' द्वारा जोड़ा गया अंतर्निहित पूल निकाला नहीं जाएगा। Http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html देखें –

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