ARC: find memory leak calling drawInRect through a block

I'm new to Instruments, but i've been successful in finding leaks before. This time, not so -- there's a 34MB leak every time I call this code! I've tried to post all the relevant code below while snipping out things like DDLogging and so on...

First, the Instruments screencap showing the issue. Note that I tried simulating a memory warning and also waiting some time, nothing changes -- this memory is permanently eaten.

PhotoManager.m:
- (void)saveImage:(UIImage*)unimage completionBlock:(void(^)(BOOL success, NSError *error))completionBlock {

    __weak typeof(self) weakSelf = self;

    dispatch_block_t work = ^{
        __block UIImage* image = [[AirprintCollagePrinter singleton] fixRotation:unimage];

        // if trial mode, always downsize and watermark image
        if( [PurchaseHelper singleton].getPurchaseLevel == PurchaseLevelTrial ) {

            dispatch_sync(_photoManagerQueue, ^{
                if( image.size.height > 1800 || image.size.width > 1200 ) {
                    image = [[AirprintCollagePrinter singleton] fitImage:image scaledToFillSize:CGSizeMake(1200, 1800)];
                }

                image = [weakSelf imageWithWatermark:image withWatermark:_watermarkImage];
            });
        }

        <snip>
    };

    if( [[NSThread currentThread] isMainThread] )
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), work);
    else
        work();
}

From the Instruments screencap you can see that AirprintCollagePrinter:fitImage is the last part of my code in the trace, so here's that:

AirprintCollagePrinter.m:
- (UIImage *)fitImage:(UIImage *)image scaledToFillSize:(CGSize)size {
    // do not upscale

    @autoreleasepool {
        if( image.size.width <= size.width && image.size.height <= size.height )
            return image;

        CGFloat scale = MIN(size.width/image.size.width, size.height/image.size.height);
        CGFloat width = image.size.width * scale;
        CGFloat height = image.size.height * scale;
        CGRect imageRect = CGRectMake(0,
                                      0,
                                      width,
                                      height);

        UIGraphicsBeginImageContextWithOptions(size, YES, 0);
        [image drawInRect:imageRect];
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage;
    }
}

... I remembered to end my image context and to wrap it in an autoreleasepool... what did I miss?

Answers


Figured it out. From the code above, it is a secondary thead (an NSOperation in fact) that is calling PhotoManager:saveImage, and it is doing so like this:

while ( true ) {
    // do work
    [PhotoManager singleton] saveImage:xyz];

    [NSThread sleepForTimeInterval:0.5];
}

The problem was that although the secondary thread's main() was using an @autoreleasepool like it is supposed to, that pool never got time to drain because the thread was always sleeping or working.

The solution was to use another @autorelease pool like this, with the sleep outside of it:

while ( true ) {
    @autoreleasepool {
        // do work
        [PhotoManager singleton] saveImage:xyz];
    }
    [NSThread sleepForTimeInterval:0.5];
}

Need Your Help

PHP image hourly

php image time random intervals

I have a PHP file that randomly generates an image from a folder on every refresh. I downloaded it from here (which also has an explanation).

WPF DataTemplate specify an alternative source

c# wpf binding datatemplate

I have a DataTemplate which is based on an XmlNode.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.