Search code examples
iosobjective-ciphonememory-leakscgimageref

CGImage memory leak


The following code works the way I want it to, but every time I call it, Instruments tells me I have one CGImage memory leak. I've been having trouble understanding what to release and when. The following is from the @interface section of my file.

CGImageRef depthImageRef;
char *depthPixels;
NSData *depthData;

In the next code, I basically alter depthPixels and then store the result in a new depthImageRef.

size_t width                    = CGImageGetWidth(depthImageRef);
size_t height                   = CGImageGetHeight(depthImageRef);
size_t bitsPerComponent         = CGImageGetBitsPerComponent(depthImageRef);
size_t bitsPerPixel             = CGImageGetBitsPerPixel(depthImageRef);
size_t bytesPerRow              = CGImageGetBytesPerRow(depthImageRef);


for (int row = 0; row < height; row += 1) {

    for (int bitPlace = 0; bitPlace < bytesPerRow; bitPlace += 4) {

        CGPoint pointForHeight = CGPointMake((bitPlace/4) - place.x, row - place.y);

        int distanceFromLocation = sqrt(pow(place.x - pointForHeight.x, 2) + pow(place.y - pointForHeight.y, 2));
        int newHeight = blopHeight - (5 - sizeSlider.value)*distanceFromLocation;

        NSInteger baseBitPlace = row*bytesPerRow + bitPlace;

        CGFloat currentHeight = depthPixels[baseBitPlace];
        if (newHeight > currentHeight) {
            depthPixels[baseBitPlace] = newHeight;
        }
    }
}

CGColorSpaceRef colorspace      = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo         = CGImageGetBitmapInfo(depthImageRef);
CGDataProviderRef provider      = CGDataProviderCreateWithData(NULL, depthPixels, [depthData length], NULL);

depthImageRef = CGImageCreate (
                               width,
                               height,
                               bitsPerComponent,
                               bitsPerPixel,
                               bytesPerRow,
                               colorspace,
                               bitmapInfo,
                               provider,
                               NULL,
                               false,
                               kCGRenderingIntentDefault
                               );
CGColorSpaceRelease(colorspace);
CFRelease(provider);
CGDataProviderRelease(provider);

I believe the leak is created because I keep creating depthImageRef but never release it. I've tried putting CGImageRelease(depthImageRef) at various places and setting depthImageRef to nil, and usually when I do this I get crashes. Thanks!


Solution

  • If you are recreating depthImageRef multiple times by calling the above code, you are leaking memory by repeatedly creating CGImageRefs and not releasing them. If you are recreating dataImageRef you should release the old image immediately before creating the new one.

    // works, even if depthImageRef is NULL such as in the initial case.
    CGImageRelease(depthImageRef);
    depthImageRef = CGImageCreate ( //...
    

    Also be sure you are calling CGImageRelease in your dealloc method and freeing your depthPixels buffer in dealloc. CGDataProviderRelease won't release the buffer you pass into it unless you pass a callback to already release that buffer. You don't need the call for CFRelease(provider) since you are calling CGDataProviderRelease(provider).