Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoreleasePool not catching breakpoints, no warnings, no reporting in Instruments Leaks

I'm trying to catch scenarios if there is no autorelease pool in place.
This is my test app.

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [self performSelectorInBackground:@selector(bgOperation:) withObject:nil];
}

- (void)bgOperation:(id)obj
{
    NSString *string [[[NSString alloc] init] autorelease];
}

I've tried setting the breakpoint objc_autoreleaseNoPool.
I've tried profiling with Instruments / Leaks.
OSX 10.7.5 XCode 4.3.3 Targeting 10.6, AutomaticRefCounting = NO, GarbageCollection = Unsupported.

I understand NSApplication includes it's own autorelease pool. But my understanding was that each call to performSelectorInBackground: needed it's own autorelease pool.

Update from the suggestions:
I tried this..
in main.m, no luck.

int main(int argc, char *argv[])
{
    NSString *junk = [[[NSString alloc]init]autorelease];
    return NSApplicationMain(argc, (const char **)argv);
}

And this..
In my appDelegate, also no result.

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [NSThread detachNewThreadSelector:@selector(bgOperation:)
                             toTarget:self
                           withObject:nil];
}

And this..
With pthreads in my main.m

void *doJunk(void *ptr){
  NSString *junk = [[[NSString alloc]initWithString:@"string with no pool"]autorelease];
  NSLog(@"%@", junk);
  pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
  pthread_t thread;
  pthread_create(&thread, NULL, doJunk, NULL);
  return NSApplicationMain(argc, (const char **)argv);
}

I understand that due to the OS level maybe nothing is leaking (still haven't confirmed), but when I target 10.6 I see a number of "No Pool" messages in the logs. If it only leaks due to the OS level, then I need a way to catch these scenarios in 10.7 when I'm targeting 10.6 but using the 10.7 SDK.

like image 386
estobbart Avatar asked Dec 19 '12 16:12

estobbart


2 Answers

performSelectorInBackground: is probably using a dispatch_queue nowadays, which automatically sets up an autorelease pool for you. Try launching a new NSThread directly and see if that causes leaks for you.

You could also try moving your code to before NSApplicationMain, which would have the same behaviour.

like image 131
Jesse Rusak Avatar answered Oct 21 '22 19:10

Jesse Rusak


According to the documentation it's still mandatory to create a pool in this situation.

The performSelectorInBackground:withObject: method creates a new detached thread and uses the specified method as the entry point for the new thread.

[...]

The effect of calling this method is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object, selector, and parameter object as parameters. The new thread is spawned immediately using the default configuration and begins running. Inside the selector, you must configure the thread just as you would any thread. For example, you would need to set up an autorelease pool (if you were not using garbage collection) and configure the thread’s run loop if you planned to use it.

Then according to the documentation of NSThread for

+ (void)detachNewThreadSelector:(SEL)aSelector
                       toTarget:(id)aTarget
                     withObject:(id)anArgument

For non garbage-collected applications, the method aSelector is responsible for setting up an autorelease pool for the newly detached thread and freeing that pool before it exits.

Therefore, unless Apple changed the implementation without documenting it (very unlikely), creating a pool is still mandatory for any selector executed in a separate thread which makes use of autorelease.

In order to verify whether the doc is stating the truth, try to replace your call

[self performSelectorInBackground:@selector(bgOperation:) withObject:nil];

with

[NSThread detachNewThreadSelector:@selector(bgOperation:) toTarget:self withObject:nil];

According to the doc the two above calls should be equivalent. You may discover that they are not.

like image 1
Gabriele Petronella Avatar answered Oct 21 '22 17:10

Gabriele Petronella