2014-07-25 2 views
7

나는 내 자신의 스레드에 대한 autoreleasepool를 작성하지 않은이NSThread가 자동으로 자동 저장 풀을 자동 생성합니까?

- (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]); 
} 

같은 테스트 코드를 가지고 있지만, 때 스레드 종료, 객체 "내"단지 dealloc.why?

나는 내 자신의 autoreleasepool를 만들

- (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]); 
} 

아래로 내 테스트 코드를 변경하지만 때 스레드 종료를 배출하지 비록. 객체 "my"는 여전히 dealloc 일 수 있습니다. 왜?

나는 ARC

+0

내 개체가 출시되는 것을 어떻게 말하고 있습니까? –

+0

필요한 정보를 얻을 수 있습니까? –

+0

왜냐하면 나는 "my"의 dealloc 메쏘드에 breakpoint를 가지고 있기 때문이다. – eliudnis

답변

1

Apple documentation says (4 단락)를 사용하지 Xcode5 및 사용

당신은 평소 ALLOC 및 초기화 메시지와 함께 NSAutoreleasePool 객체를 생성하고 (드레인 폐기 또는 릴리스 - 차이점을 이해하려면 가비지 수집을 참조하십시오. 자동 해제 풀을 보유 할 수 없으므로 (자동 갱신은 보유 및 자동 해제 참조) 풀을 배수하면 궁극적으로 해제됩니다. 은 (메소드 또는 함수 또는 루프 본문)과 동일한 컨텍스트의 자동 실행 풀을 항상 배출해야합니다 ( ). 자세한 내용은 자동 복구 풀 블록 사용을 참조하십시오.

16

것은이 문서화되지,하지만 대답은 OS X 10.9+ 및 iOS 7+에 것으로 보인다.

Objective-C 런타임은 open-source이므로 소스를 읽고 상황을 확인하십시오. 현재 스레드에서 풀없이 autorelease을 수행하면 런타임의 최신 버전 (646, OS X 10.10 및 iOS 8과 함께 제공됨)이 실제로 풀을 추가합니다. 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를. 첫 번째 풀이 푸시되면 autorelease 스택이 설정됩니다. 그러나 코드에서 볼 수 있듯이 DebugMissingPools 환경 변수가 설정되지 않은 경우 (기본적으로 설정되지 않음) autorelease가 풀없이 완료되면 autorelease 스택을 설정 한 다음 풀을 푸시합니다. POOL_SENTINEL).

비슷하게 스레드가 파괴되어 스레드 로컬 저장소가 파괴 될 때 (다른 코드를 보지 않고 따르기는 조금 어렵지만 관련 부분입니다) autorelease 스택의 모든 것을 해제합니다 (즉, pop(0);가하는 일입니다) 그래서 마지막 풀을 팝업으로 사용자에 의존하지 않습니다 또한

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

(X 10.9 및 iOS 7 OS와 함께 제공 551.1) 런타임의 이전 버전, 이 내용은 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); 
} 

하지만 그 전의 버전 (OS X 10과 함께 제공된 532.2.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의.

기본적으로 OS X 10.9 이상 또는 iOS 7 이상에서 실행중인 경우 풀이없는 스레드에서 자동 복구가 누출로 이어지지 않아야합니다. 이것은 문서화되지 않았기 때문에 내부 구현에 대한 세부 사항이므로 Apple이 향후 OS에서이를 변경할 수 있으므로주의해야합니다. 그러나, 단순히 자동 응답 풀이 작동하는 방식을 완전히 다시 작성하지 않는 한,이 기능이 간단하고 장점이 있으며 단점도없는 이유로이 기능을 제거하는 이유는 없습니다.

+0

뛰어난 답. 위대한 탐정 일. 게시 해 주셔서 감사합니다. (투표 됨) –

+1

자동 정리는 주 스레드에 대해 발생하지 않습니다. 클린업 함수'tls_dealloc'는'pthread_key_init_np'에 대한 호출에 의해 추가 된 스레드 로컬 저장소 (TLS) 소멸자입니다. 이러한 소멸자는'pthread_exit'에서 호출됩니다.이 스레드는 스레드가 시작 루틴에서 복귀 할 때 암시 적으로 호출되지만 주 스레드의 경우에는 암시 적으로 호출되지 않습니다. 그래서'autoreleaseNoPage'에 의해 추가 된 암시 적 풀은 빠져 나가지 않을 것입니다. http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html을 참조하십시오. –