Swift 3 CGContext内存泄漏

3

我正在使用CGBitMapContext()将颜色空间转换为ARGB并获取像素数据值,我为位图上下文分配了空间,并在完成后释放它,但仍然在Instruments中看到内存泄漏。我认为我可能做错了什么,因此需要帮助。

以下是ARGBBitmapContext函数:

func createARGBBitmapContext(width: Int, height: Int) -> CGContext {
    var bitmapByteCount = 0
    var bitmapBytesPerRow = 0

    //Get image width, height
    let pixelsWide = width
    let pixelsHigh = height

    bitmapBytesPerRow = Int(pixelsWide) * 4
    bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)


    let colorSpace = CGColorSpaceCreateDeviceRGB()
    // Here is the malloc call that Instruments complains of
    let bitmapData = malloc(bitmapByteCount)


    let context = CGContext(data: bitmapData, width: pixelsWide, height: pixelsHigh, bitsPerComponent: 8, bytesPerRow: bitmapBytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue)

    // Do I need to free something here first?
    return context!
}

这里我使用上下文来获取所有像素值作为UInt8列表(也是内存泄漏的地方)。

extension UIImage {

    func ARGBPixelValues() -> [UInt8] {
        let width = Int(self.size.width)
        let height = Int(self.size.height)
        var pixels = [UInt8](repeatElement(0, count: width * height * 3))

        let rect = CGRect(x: 0, y: 0, width: width, height: height)
        let context = createARGBBitmapContext(inImage: self.cgImage!)
        context.clear(rect)
        context.draw(self.cgImage!, in: rect)

        var location = 0

        if let data = context.data {

            while location < (width * height) {
                let arrOffset = 3 * location
                let offset = 4 * (location)

                let R = data.load(fromByteOffset: offset + 1, as: UInt8.self)
                let G = data.load(fromByteOffset: offset + 2, as: UInt8.self)
                let B = data.load(fromByteOffset: offset + 3, as: UInt8.self)

                pixels[arrOffset]   = R
                pixels[arrOffset+1] = G
                pixels[arrOffset+2] = B

                location += 1
            }

            free(context.data) // Free the data consumed, perhaps this isn't right?
        }

        return pixels
    }
}

Instruments报告了一个1.48MiB的malloc错误,这与我的图像大小(540 x 720)相符。我释放了数据,但显然这并不正确。

我应该提到,我知道你可以将nil传递给CGContext init(它会管理内存),但我更想知道为什么使用malloc会有问题,是否还有其他需要注意的事项(我更熟悉Obj-C)。


我没有看到任何释放上下文本身的代码。当您完成上下文操作时,您需要调用 CGContextRelease - Dave Weston
据我所知,CGContextRelease在Swift 3中不可用,因为它会自行释放(或者至少应该如此)。我不认为我创建了任何循环引用,所以它不应该出现这种情况。 - Joel Cummings
1
你找到答案了吗? - return true
1个回答

2

因为CoreGraphics不受ARC(像所有其他C库一样)管理,所以即使在Swift中,您也需要使用autorelease来包装代码。特别是如果您不在主线程上(如果涉及CoreGraphics...则不应该),那么userInitiated或更低的优先级是适当的。

func myFunc() {  
    for _ in 0 ..< makeMoneyFast {
        autoreleasepool {
            // Create CGImageRef etc...
            // Do Stuff... whir... whiz... PROFIT!
        }
    }
}

如果您关心的话,您的Objective-C代码也应该像这样进行包装:

BOOL result = NO;
NSMutableData* data = [[NSMutableData alloc] init];
@autoreleasepool {
    CGImageRef image = [self CGImageWithResolution:dpi
                                          hasAlpha:hasAlpha
                                     relativeScale:scale];

    NSAssert(image != nil, @"could not create image for TIFF export");

    if (image == nil)
        return nil;

    CGImageDestinationRef destRef = CGImageDestinationCreateWithData((CFMutableDataRef)data, kUTTypeTIFF, 1, NULL);
    CGImageDestinationAddImage(destRef, image, (CFDictionaryRef)options);
    result = CGImageDestinationFinalize(destRef);
    CFRelease(destRef);
}

if (result) {
    return [data copy];
} else {
    return nil;
}

有关详细信息,请参见此答案


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接