2014-07-25 20 views
7

Tôi có mã kiểm tra như thế nàyNSThread có tự động tạo autoreleasepool ngay bây giờ không?

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

tôi không tạo ra bất kỳ autoreleasepool cho chủ đề của riêng tôi, nhưng khi thread xuất cảnh, đối tượng "của tôi" chỉ dealloc.why?

mặc dù tôi thay đổi mã thử nghiệm của tôi như sau

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

tôi tạo autoreleasepool của riêng tôi nhưng không thoát nó khi lối ra chủ đề. đối tượng "của tôi" vẫn có thể dealloc anyway. tại sao?

tôi sử dụng Xcode5 và không sử dụng ARC

+0

Bạn nói đối tượng của mình được giải phóng như thế nào? –

+0

bạn có thể nhận thông tin bắt buộc không? –

+0

vì tôi có điểm ngắt trong phương thức dealloc của đối tượng "của tôi" – eliudnis

Trả lời

1

Apple documentation says (4 thứ đoạn):

Bạn tạo một đối tượng NSAutoreleasePool với alloc thông thường và điệp init và vứt bỏ nó với cống (hoặc phát hành — để hiểu số sự khác biệt, xem Bộ sưu tập rác). Vì bạn không thể giữ lại hồ bơi tự động trả lời (hoặc tự động sửa nó — xem giữ lại và tự động lấy lại dữ liệu), thoát khỏi một hồ bơi cuối cùng có tác dụng giải quyết nó. Bạn phải luôn luôn thoát khỏi một nhóm tự động trả lời trong cùng một ngữ cảnh (gọi phương thức hoặc hàm hoặc vòng lặp) mà đã được tạo . Xem Sử dụng nhóm khối tự động phát hành để biết thêm chi tiết.

16

Nó không được ghi lại nhưng câu trả lời dường như là , trên OS X 10.9+ và iOS 7+.

Thời gian chạy mục tiêu-C là open-source để bạn có thể đọc nguồn để xem điều gì đang diễn ra. Phiên bản mới nhất của thời gian chạy (646, được vận chuyển với OS X 10.10 và iOS 8) thực sự thêm một nhóm nếu bạn thực hiện một autorelease mà không có một nhóm trên luồng hiện tại. Trong 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); 
} 

Chức năng này được gọi khi bạn đẩy hồ bơi đầu tiên (trong trường hợp điều đẩy là POOL_SENTINEL), hoặc bạn autorelease không có hồ bơi. Khi các hồ bơi đầu tiên được đẩy, nó thiết lập stack autorelease. Nhưng như bạn thấy từ mã, miễn là biến môi trường DebugMissingPools không được thiết lập (nó không được thiết lập theo mặc định), khi autorelease được thực hiện mà không có pool, nó cũng thiết lập stack autorelease, và sau đó đẩy một pool (đẩy một POOL_SENTINEL).

Tương tự, (hơi khó theo dõi mà không nhìn vào mã khác, nhưng đây là phần liên quan) khi chuỗi bị hủy (và lưu trữ Thread-Local bị hủy), nó giải phóng mọi thứ trong ngăn xếp tự động (đó là những gì các pop(0); không) vì vậy nó không dựa vào người dùng để bật hồ bơi lần cuối:

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

các phiên bản trước của runtime (551,1, mà đi kèm với OS X 10.9 và iOS 7), cũng đã làm điều này, như bạn có thể thấy từ số 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); 
} 

Nhưng phiên bản trước đó (532.2, đi kèm với OS X 10.8 và 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); 
} 

Lưu ý rằng các công trình trên cho bất kỳ pthread s, không chỉ NSThread s.

Vì vậy, về cơ bản, nếu bạn đang chạy trên OS X 10.9+ hoặc iOS 7+, tự động phát hành trên chuỗi không có hồ bơi sẽ không dẫn đến rò rỉ. Đây không phải là tài liệu và là một chi tiết thực hiện nội bộ, vì vậy hãy cẩn thận dựa vào điều này như Apple có thể thay đổi nó trong một hệ điều hành trong tương lai. Tuy nhiên, tôi không thấy lý do nào tại sao họ sẽ xóa tính năng này vì nó đơn giản và chỉ có lợi ích và không có nhược điểm, trừ khi họ viết lại hoàn toàn cách thức hoạt động của các nhóm tự động làm việc hoặc điều gì đó.

+0

Câu trả lời nổi bật. Công việc thám tử vĩ đại. Cảm ơn vì đăng. (Bình chọn) –

+1

Lưu ý rằng chức năng dọn dẹp tự động không * không * xảy ra với chủ đề chính. Hàm cleanup 'tls_dealloc' là một destructor thread-local-storage (TLS), được thêm vào bởi một cuộc gọi đến' pthread_key_init_np'. Các destructors này được gọi từ 'pthread_exit', được gọi ngầm khi một luồng trả về từ thường trình bắt đầu của nó, nhưng không được gọi trong trường hợp của luồng chính. Vì vậy, hồ bơi ngầm được thêm bởi 'autoreleaseNoPage' sẽ không được rút ra. Xem http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html –

Các vấn đề liên quan