3

Does ARC no longer require @autoreleasepool on methods invoked in a background thread? The following code suppose to cause a memory leak unless doStuff is wrapped with an @autorelease pool, but when I run instruments it shows that User gets allocated and it gets deallocated at the end of the runloop.

- (IBAction)buttonClicked:(id)sender {
    [self performSelectorInBackground:@selector(doStuff) withObject:nil];
}

- (void)doStuff {
    User *user = [[User alloc] init];
    NSLog(@"%@", user);
}
aryaxt
  • 76,198
  • 92
  • 293
  • 442
  • 1
    Your `user` instance isn't autoreleased so it won't leak. ARC will add an explicit call to `release` at the end of the `doStuff` method. Try your test with an autoreleased object such as `NSArray *array = [NSArray array];`. – rmaddy Aug 12 '14 at 04:42
  • I tried [NSArray array], won't cause a leak – aryaxt Aug 12 '14 at 04:45
  • try something more complicated (function from file compiled with MRC). otherwise compiler may eliminate all `autorelease` call. – Bryan Chen Aug 12 '14 at 04:50
  • [NSArray array] returns a singleton, so it doesn't leak. – Nikolai Ruhe Aug 12 '14 at 04:53
  • @NikolaiRuhe What do you mean? `[NSArray array]` is a _class method_ that returns an _instance_ of `NSArray`, not a singleton. – CrimsonChris Aug 12 '14 at 04:55
  • @NikolaiRuhe is correct. (lldb) po [NSArray array] <__NSArrayI 0x7fc82a402810> (lldb) po [NSArray array] <__NSArrayI 0x7fc82a402810> [NSMutableArray array] returns different instances – aryaxt Aug 12 '14 at 04:56
  • @NikolaiRuhe Good catch on the `NSArray array` singleton. Makes sense since it is immutable. @aryaxt - Do you get a leak with the mutable array? – rmaddy Aug 12 '14 at 05:00
  • Oh wow, I never would have guessed that all empty NSArray's are the same object, must be an optimization. I _definitely_ wouldn't depend on that behavior though. It's not documented so technically it's undefined behavior. – CrimsonChris Aug 12 '14 at 05:01
  • @rmaddy Nope can't get a leak in any way. Maybe ARC really handles it. I really want it to leak, it bothers me so bad :) – aryaxt Aug 12 '14 at 05:02
  • 1
    @aryaxt Why do you expect it to leak? Nothing in the code you've shared has any leaks under ARC. – CrimsonChris Aug 12 '14 at 05:03
  • 1
    @CrimsonChris I couldn't find anything in the documentation that says ARC handles this, so don't want to trust it yet – aryaxt Aug 12 '14 at 05:04
  • @aryaxt It doesn't matter what thread you are on, ARC behaves the same. – CrimsonChris Aug 12 '14 at 05:08
  • @aryaxt Your primary concern with ARC should be to understand the difference between weak, strong, and unsafe_unretained. After that, the main enemy is retain cycles. Blocks are tricky so if you use them often look into weakify/strongify. http://aceontech.com/objc/ios/2014/01/10/weakify-a-more-elegant-solution-to-weakself.html – CrimsonChris Aug 12 '14 at 05:12
  • You may wish to see http://stackoverflow.com/questions/12575010/using-arc-is-it-fatal-not-to-have-an-autorelease-pool-for-every-thread The 2nd answer actually has a more direct answer but both are a good read. – rmaddy Aug 12 '14 at 05:14
  • Ok great. so the final answer is an autoreleasePool is automatically created for new threads under ARC – aryaxt Aug 12 '14 at 05:22
  • 1
    @aryaxt This conclusion is based on observation and the assumption that it will always be like that (every OS, every release, every device, every other circumstance). I would not build my software on ice this thin, especially as the documentation states otherwise. – Nikolai Ruhe Aug 12 '14 at 07:52

3 Answers3

3

While there might be hints to an existing autorelease pool in NSThread's implementation there is no such guarantee the documentation. In contrary, the documentation explicitly states otherwise:

performSelectorInBackground:withObject:

The method represented by aSelector must set up the thread environment just as you would for any other new thread in your program.

Threading Programming Guide

If your application uses the managed memory model [MRC and ARC, as opposed to Garbage Collection], creating an autorelease pool should be the first thing you do in your thread entry routine.

Conclusion: While in some specific scenarios there might be an autorelease pool in place it's not advisable to rely on this fact. It's undocumented behavior and can change with every release of the OS or other circumstances. It should generally be avoided in shipping code.

Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
1

I used the following test app:

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end

#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad{
    [super viewDidLoad];
    [self performSelectorInBackground:@selector(doStuff) withObject:nil];
}
- (void)doStuff {
    NSMutableArray *ar = [NSMutableArray array];
    for (int i=0; i<1000000; i++) {
        ar[i] = [NSString stringWithFormat:@"%i", i];
    }
}
@end

Profiling it with the Allocation instrument, I get the following result:
enter image description here
In the 8th line of the call tree, an autorelease pool is used, although I did not set up one in my code. Also, the memory allocated by the background thread seems to be released.
It thus looks as if the background thread has an autorelease pool installed.

EDIT (see comment below):

This does not mean, however, that it is not necessary to install autorelease pools for threads, since the behavior shown above is not documented, as far as I know.

Reinhard Männer
  • 14,022
  • 5
  • 54
  • 116
  • 1
    While not false in itself, this answer is misleading in the sense of the question ("Does ARC no longer require @autoreleasepool"). – Nikolai Ruhe Aug 12 '14 at 07:54
  • I did not think that my answer could be misleading. But if so, I will edit it. – Reinhard Männer Aug 12 '14 at 07:59
  • 1
    Your answer led the OP to the conclusion "Ok great. so the final answer is an autoreleasePool is automatically created for new threads under ARC" (see comments). That's just wrong. – Nikolai Ruhe Aug 12 '14 at 08:01
-2

Actually, that code is supposed to leak memory (under MRC) if you don't add an autorelease (which is pretty much just asking for trouble). But I'm going to answer your question as you asked it anyways.

ARC is supposed to eliminate the need for any sort of memory management (except for blocks and a lot of other gotchas, but whatever). But there are still autoreleased objects. @autoreleasepool is particularly useful in tight loops, etc. There are still pools to drain, you just don't have to add autorelease to objects yourself.

Aehmlo
  • 930
  • 1
  • 8
  • 20