CreateARGBBitmapContext导致内存泄漏

时间:2014-03-24 14:56:13

标签: iphone ios7 memory-leaks

我使用以下代码为CoreImage的CICircularWrap过滤器创建了类似的效果,该过滤器不适用于iOS。这是造成内存泄漏的代码。我已经发布了上下文以及它创建的图像。对于我的生活,我无法发现泄漏。任何 输入将非常感激。感谢。

以下是调用该方法的方法:

UIImage *circularWrapImage = [UIImage imageWithCGImage:circularWrap(image.CGImage, 0, 1000, 0, YES, YES)];

实际方法:

CGContextRef CreateARGBBitmapContext (size_t pixelsWide, size_t pixelsHigh){
CGContextRef    context = NULL;
CGColorSpaceRef colorSpace;
void *          bitmapData;
int             bitmapByteCount;
int             bitmapBytesPerRow;

// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow   = (int)(pixelsWide * 4);
bitmapByteCount     = (int)(bitmapBytesPerRow * pixelsHigh);

// Use the generic RGB color space.
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
{
    fprintf(stderr, "Error allocating color space\n");
    return NULL;
}

// Allocate memory for image data. This is the destination in memory
// where any drawing to the bitmap context will be rendered.
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
    fprintf (stderr, "Memory not allocated!");
    CGColorSpaceRelease( colorSpace );
    return NULL;
}

// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
context = CGBitmapContextCreate (bitmapData,
                                 pixelsWide,
                                 pixelsHigh,
                                 8,      // bits per component
                                 bitmapBytesPerRow,
                                 colorSpace,
                                 kCGImageAlphaPremultipliedFirst);
if (context == NULL)
{
    free (bitmapData);
    fprintf (stderr, "Context not created!");
}

// Make sure and release colorspace before returning
CGColorSpaceRelease( colorSpace );

return context;

CGContextRelease(context);}

CGImageRef circularWrap3(CGImageRef inImage,CGFloat bottomRadius, CGFloat topRadius, CGFloat startAngle, BOOL clockWise, BOOL interpolate){
//if(topRadius < 0 || bottomRadius < 0) return NULL;

// Create the bitmap context
int w = (int)CGImageGetWidth(inImage);
int h = (int)CGImageGetHeight(inImage);

//result image side size (always a square image)
int resultSide = 2*MAX(topRadius, bottomRadius);
CGContextRef cgctx1 = CreateARGBBitmapContext(w,h);
CGContextRef cgctx2 = CreateARGBBitmapContext(resultSide,resultSide);

if (cgctx1 == NULL || cgctx2 == NULL)
{
    return NULL;
}

// Get image width, height. We'll use the entire image.
CGRect rect = {{0,0},{w,h}};

// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(cgctx1, rect, inImage);

// Now we can get a pointer to the image data associated with the bitmap
// context.
int *data1 = CGBitmapContextGetData (cgctx1);
int *data2 = CGBitmapContextGetData (cgctx2);

int resultImageSize = resultSide*resultSide;
double temp;
for(int *p = data2, pos = 0;pos<resultImageSize;p++,pos++)
{
    *p = 0;
    int x = pos%resultSide-resultSide/2;
    int y = -pos/resultSide+resultSide/2;
    CGFloat phi = modf(((atan2(x, y)+startAngle)/2.0/M_PI+0.48),&temp);
    if(!clockWise) phi = 1-phi;
    phi*=w;
    CGFloat r = ((sqrtf(x*x+y*y))-topRadius)*h/(bottomRadius-topRadius);
    if(phi>=0 && phi<w && r>=0 && r<h)
    {
        if(!interpolate || phi >= w-1 || r>=h-1)
        {
            //pick the closest pixel
            *p = data1[(int)r*w+(int)phi];
        }
        else
        {
            double dphi = modf(phi, &temp);
            double dr = modf(r, &temp);

            int8_t* c00 = (int8_t*)(data1+(int)r*w+(int)phi);
            int8_t* c01 = (int8_t*)(data1+(int)r*w+(int)phi+1);
            int8_t* c10 = (int8_t*)(data1+(int)r*w+w+(int)phi);
            int8_t* c11 = (int8_t*)(data1+(int)r*w+w+(int)phi+1);

            //interpolate components separately
            for(int component = 0; component < 4; component++)
            {
                double avg = ((*c00 & 0xFF)*(1-dphi)+(*c01 & 0xFF)*dphi)*(1-dr)+((*c10 & 0xFF)*(1-dphi)+(*c11 & 0xFF)*dphi)*dr;
                *p += (((int)(avg))<<(component*8));
                c00++; c10++; c01++; c11++;
            }
        }
    }
}

CGImageRef result = CGBitmapContextCreateImage(cgctx2);

// When finished, release the context
CGContextRelease(cgctx1);
CGContextRelease(cgctx2);
// Free image data memory for the context
if (data1) free(data1);
if (data2) free(data2);

return result;

CGImageRelease(inImage);
CGImageRelease(result);

}

Screenshot of errors

1 个答案:

答案 0 :(得分:1)

泄漏是最后3行......

return result;

CGImageRelease(inImage);
CGImageRelease(result);

由于return

,2个版本永远不会被调用

你需要做这样的事情......

UIImage *image = [UIImage imageWithCGImage: result];
CGImageRelease(inImage); 
CGImageRelease(result); 
return image;

更新:你还有一些泄漏...

您的通话需要看起来像这样

CGImageRef imageRef = circularWrap3(timeLapseImage.CGImage, 0, 1000, 0, YES, YES);
UIImage *circularWrapImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);

和你的方法......

CGContextRef CreateARGBBitmapContext (size_t pixelsWide, size_t pixelsHigh) {
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    // Declare the number of bytes per row. Each pixel in the bitmap in this
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and
    // alpha.
    bitmapBytesPerRow   = (int)(pixelsWide * 4);
    bitmapByteCount     = (int)(bitmapBytesPerRow * pixelsHigh);

    // Use the generic RGB color space.
    colorSpace = CGColorSpaceCreateDeviceRGB(); 
    if (colorSpace == NULL)
    {
        fprintf(stderr, "Error allocating color space\n");
        return NULL;
    }

    // Allocate memory for image data. This is the destination in memory
    // where any drawing to the bitmap context will be rendered.
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL)
    {
        fprintf (stderr, "Memory not allocated!");
        CGColorSpaceRelease( colorSpace );
        return NULL;
    }

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
    // per component. Regardless of what the source image format is
    // (CMYK, Grayscale, and so on) it will be converted over to the format
    // specified here by CGBitmapContextCreate.
    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,      // bits per component
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst);
    if (context == NULL)
    {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
    }

    // Make sure and release colorspace before returning
    CGColorSpaceRelease( colorSpace );

    return context;

    // This is not needed as you release the contexts later on and wouldn't be called anyway
    //CGContextRelease(context);
}

CGImageRef circularWrap3(CGImageRef inImage,CGFloat bottomRadius, CGFloat topRadius, CGFloat startAngle, BOOL clockWise, BOOL interpolate)
{
    //if(topRadius < 0 || bottomRadius < 0) return NULL;

    // Create the bitmap context
    int w = (int)CGImageGetWidth(inImage);
    int h = (int)CGImageGetHeight(inImage);

    //result image side size (always a square image)
    int resultSide = 2*MAX(topRadius, bottomRadius);
    CGContextRef cgctx1 = CreateARGBBitmapContext(w,h);
    CGContextRef cgctx2 = CreateARGBBitmapContext(resultSide,resultSide);

    if (cgctx1 == NULL || cgctx2 == NULL)
    {
        //   ********************************************* 
        //    YOU COULD BE LEAKING HERE AS WELL IF ONE OF THEM IS NOT NULLL
        return NULL;
    }

    // Get image width, height. We'll use the entire image.
    CGRect rect = {{0,0},{w,h}};

    // Draw the image to the bitmap context. Once we draw, the memory
    // allocated for the context for rendering will then contain the
    // raw image data in the specified color space.
    CGContextDrawImage(cgctx1, rect, inImage);

    // Now we can get a pointer to the image data associated with the bitmap
    // context.
    int *data1 = CGBitmapContextGetData (cgctx1);
    int *data2 = CGBitmapContextGetData (cgctx2);

    int resultImageSize = resultSide*resultSide;
    double temp;
    for(int *p = data2, pos = 0;pos<resultImageSize;p++,pos++)
    {
        *p = 0;
        int x = pos%resultSide-resultSide/2;
        int y = -pos/resultSide+resultSide/2;
        CGFloat phi = modf(((atan2(x, y)+startAngle)/2.0/M_PI+0.48),&temp);
        if(!clockWise) phi = 1-phi;
        phi*=w;
        CGFloat r = ((sqrtf(x*x+y*y))-topRadius)*h/(bottomRadius-topRadius);
        if(phi>=0 && phi<w && r>=0 && r<h)
        {
            if(!interpolate || phi >= w-1 || r>=h-1)
            {
                //pick the closest pixel
                *p = data1[(int)r*w+(int)phi];
            }
            else
            {
                double dphi = modf(phi, &temp);
                double dr = modf(r, &temp);

                int8_t* c00 = (int8_t*)(data1+(int)r*w+(int)phi);
                int8_t* c01 = (int8_t*)(data1+(int)r*w+(int)phi+1);
                int8_t* c10 = (int8_t*)(data1+(int)r*w+w+(int)phi);
                int8_t* c11 = (int8_t*)(data1+(int)r*w+w+(int)phi+1);

                //interpolate components separately
                for(int component = 0; component < 4; component++)
                {
                    double avg = ((*c00 & 0xFF)*(1-dphi)+(*c01 & 0xFF)*dphi)*(1-dr)+((*c10 & 0xFF)*(1-dphi)+(*c11 & 0xFF)*dphi)*dr;
                    *p += (((int)(avg))<<(component*8));
                    c00++; c10++; c01++; c11++;
                 }
            }
        }
    }

    CGImageRef result = CGBitmapContextCreateImage(cgctx2);

    // When finished, release the context
    CGContextRelease(cgctx1);
    CGContextRelease(cgctx2);
    // Free image data memory for the context
    if (data1) free(data1);
    if (data2) free(data2);

    CGImageRelease(inImage); 
    return result;
}