Question

I have come across an issue when loading different NSImages repeatedly in an application written using Automatic Reference Counting. It seems as though ARC is not releasing the image objects correctly, and instead the memory usage increases as the list is iterated until the iteration is complete, at which point the memory is freed.

I am seeing up to 2GB of memory being used through the process in some cases. There's a good discussion on SO on a very similar issue which ends up putting the process in an NSAutoReleasePool and releasing the image and draining the pool. This works for me as well if I don't use ARC, but it is not possible to make calls to these objects / methods in ARC.

Is there any way to make this work in ARC as well? It seems as though ARC should be figuring this out all by itself - which makes me think that the fact that these objects are not getting released must be a bug is OS X. (I'm running Lion with XCode 4.2.1).

The kind of code which is causing the issue looks like this:

+(BOOL)checkImage:(NSURL *)imageURL
{
    NSImage *img = [[NSImage alloc] initWithContentsOfURL:imageURL];
    if (!img)
         return NO;

    // Do some processing
    return YES;
}

This method is called repeatedly in a loop (for example, 300 times). Profiling the app, the memory usage continues to increase with 7.5MB alloced for each image. If ARC is not used, the following can be done (as suggested in this topic):

+(BOOL)checkImage:(NSURL *)imageURL
{
    NSAutoReleasePool *apool = [[NSAutoReleasePool alloc] init];
    NSImage *img = [[NSImage alloc] initWithContentsOfURL:imageURL];
    if (!img)
         return NO;

    // Do some processing

    [img release];
    [apool drain];

    return YES;
}

Does anyone know how to force ARC to do the memory cleaning? For the time being, I have put the function in a file which is compiled with -fno-objc-arc passed in as a compiler flag. This works OK, but it would be nice to have ARC do it for me.

Was it helpful?

Solution

use @autoreleasepool, like so:

+(BOOL)checkImage:(NSURL *)imageURL
{
    @autoreleasepool { // << push a new pool on the autotrelease pool stack
      NSImage *img = [[NSImage alloc] initWithContentsOfURL:imageURL];
      if (!img) {
         return NO;
      }
      // Do some processing
    } // << pushed pool popped at scope exit
    return YES;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top