Question

I have a weird crash in my application without any trace. this is probably a memory related problem but with very little information & I'm not sure how to proceed or fix it. If it wasnt for instruments would have been left with no clue what so ever.

I have an image array (in this example an array of size 2) where I load an image, create an image context & draw and save it into the array. Everytime the method is called image array objects are replaced with the new content. In instruments I see a very huge Virtual Memory usage during this method call & apparently after each call memory is not cleared & hence crashes. The project is ARC. I'll list down code below. This is all we need to recreate this issue. (the image I'm using is little big in size about 7MB, so its easier to recreate crash). Also i'm using iPad2 device.

+ (UIImage *)imageCopy:(UIImage *)src
{
    UIGraphicsBeginImageContext(src.size);
    [src drawAtPoint:CGPointZero];
    UIImage *r = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return r;
} 

- (IBAction)buttonTouch:(id)sender
{
    for (int i=0; i<2; i++)
    {
        if (i==0)
        {
            self.mImage = [UIImage imageNamed:@"LARGE_elevation.jpg"];
        }
        else
        {
            self.mImage = [UIImage imageNamed:@"LARGE_elevation2.jpg"];
        }
        // imageArray is a NSMutableArray with capacity of 2
        [imageArray setObject:[ViewController imageCopy:self.mImage] atIndexedSubscript:i];
    }
    ((UIImageView *)[self.view viewWithTag:100]).image = self.mImage;
}

Here is a screen from instruments where it crash on 2nd time after memory warnings are issued.

Instruments Screenshot

I dont see any big issue with the "imageCopy" method I'm using here.

Any help on this is really appreciated. Thanks & Cheers,

Was it helpful?

Solution

I found out that it was a cyclic reference issue. So when new content replaces the old content in the array, the past objects were still remaining. It was quite an interesting finding because in the memory leaks analyser it showed up as few KB data leak which you wont suspect as the non freed virtual memory was few hundred Megabytes (MB).

As a very abstract example.

ClassA

@property (strong) ClassB *obj

----------

ClassB

@property (strong) ClassA *obj

- (id)initWithA:(ClassA *)objA;
----------

So when you remove A neither object will be deallocated properly. In my case leak traced by the leak analyser was few KB for both of the objects even though the CoreGraphics calculations were hanging onto about 200MB data in virtual memory.

Fix was to mark the A reference in ClassB as weak.

ClassB

@property (weak) ClassA *obj

- (id)initWithA:(ClassA *)objA;

Verdict

  • Never under estimate a memory leak, no matter how big or small & arc or mrc

OTHER TIPS

The problem is probably that the method imageNamed: caches the images loaded, and there is apparently no way to clear the cache after a memory warning programmatically.
Instead of imageNamed:, you could use other methods like initWithData: that do not cache the images. You will find a detailed discussion here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top