0 Replies
      Latest reply on Feb 22, 2019 1:57 AM by eskimo
      ilowry Level 1 Level 1 (0 points)



        The documentation on NSAutoreleasePool  contains the following assertion:


        If you are making Cocoa calls outside of the Application Kit’s main thread—for example if you create a Foundation-only application or if you detach a thread—you need to create your own autorelease pool.


        It looks like yet it is not required anymore. For instance, the look at the code below:

        #import <Cocoa/Cocoa.h>
        #include <pthread.h>
        @interface MyObject : NSObject
        @property (copy, nonatomic) NSString* str;
        @implementation MyObject
        - init {
            self = [super init];
            NSLog(@"init %@", self);
            return self;
        - (void) dealloc {
            NSLog(@"dealloc %@", self);
            self.str = nil;
            [super dealloc];
        void* thread_main (void* ptr)
            MyObject* obj = (__bridge id)ptr;
            NSLog(@"%p:  %@", pthread_self(), obj.str);
            return 0;
        int main(int argc, const char* argv[argc])
            MyObject* obj = [MyObject new];
            obj.str = [@"test string" copy];
            NSLog(@"1: %@", obj.str);
            pthread_t pth;
            if (pthread_create (&pth, NULL, thread_main, (__bridge void*)obj) 
                || pthread_join(pth, NULL))
                perror("pthread: ");
            NSLog(@"2: %@", obj.str);
            return 0;


        iIf compile it with as following (with MRC):

        clang -gfull -fno-objc-arc -o test_autorelease test_autorelease.m -framework Cocoa


        it prints

        2019-02-20 17:11:40.814 test_autorelease[52994:2010949] init <MyObject: 0x7f8ed760b820>
        2019-02-20 17:11:40.814 test_autorelease[52994:2010949] 1: test string
        2019-02-20 17:11:40.815 test_autorelease[52994:2010951] 0x700005f17000:  test string
        2019-02-20 17:11:40.815 test_autorelease[52994:2010951] dealloc <MyObject: 0x7f8ed760b820>
        2019-02-20 17:11:40.815 test_autorelease[52994:2010949] 2: (null)


        So, it is clear that after printing the test string in background thread, the object was released and dealloced. If to comment line 27 with call to CFAutorelease(), the ouput is following:

        2019-02-20 17:16:03.505 test_autorelease[53053:2015162] init <MyObject: 0x7fccbfc006d0>
        2019-02-20 17:16:03.505 test_autorelease[53053:2015162] 1: test string
        2019-02-20 17:16:03.505 test_autorelease[53053:2015164] 0x700003be3000:  test string
        2019-02-20 17:16:03.505 test_autorelease[53053:2015162] 2: test string


        So the object is not deallocated.

        It looks like either documentation is not updated, or there is something I've missed.


        Could anybody please comment on this?

        • Re: Is creation of autorelease pool in non main threads not required anymore?
          Ken Thomases Level 4 Level 4 (785 points)

          By logging [NSThread callStackSymbols] in the -dealloc method, I see that the current autorelease pool for the thread is tracked using (roughly) pthread_key_create(), pthread_setspecific(), and pthread_getspecific(). Further, a destructor function was apparently registered during the pthread_key_create() call which cleans up the thread's autorelease pools.


          I would guess that CFAutorelease() and -[NSObject autorelease] end up creating the autorelease pool on demand and then it gets cleaned up on thread exit by that destructor function.


          All of that said, though, this is an implementation detail and is not in the design contract. So, you must code as though it were not true. If you believe it's just an oversight that the documentation hasn't been updated, then file a bug against the docs.

          • Re: Is creation of autorelease pool in non main threads not required anymore?
            eskimo Apple Staff Apple Staff (13,905 points)

            Some time back in the 10.7 days we started automatically setting up an autorelease pool for threads.  It’s clear that the documentation hasn’t been updated accordingly, and I’d appreciate you filing a bug about that.  Please post your bug number, just for the record.

            Ken Thomases wrote:

            All of that said, though, this is an implementation detail and is not in the design contract.

            In this case I think the intention was for folks to rely on it, and thus this is just a documentation bug.

            You still have to be careful here.  The autorelease pool doesn’t drain until the thread terminates, and if you create your own long-lived threads then you can suffer from an unbounded amount of autorelease pool buildup.  For example, if you have something like this:

            static void * mySelectLoop(void *) {
                … set up for select …
                while (1) {
                    int readyCount = select(…);
                    … dispatch to various select handlers …

            and the select handlers generate autorelease traffic, you will eventually run out of memory.

            Another edge case relates to Dispatch, where the same worker thread is used over and over again to run blocks scheduled on queues.  If those blocks create autorelease traffic, that will only be released when the worker thread terminates, which can take a while if there’s work to be done.  Thus, when working with Dispatch you should either:

            • Create an autorelease pool inside every block you schedule

            • Learn to love Dispatch constructs like DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL and dispatch_queue_attr_make_with_autorelease_frequency

            Share and Enjoy

            Quinn “The Eskimo!”
            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
            let myEmail = "eskimo" + "1" + "@apple.com"