簡體   English   中英

使用malloc的內存泄漏/使用arc釋放

[英]memory leak with malloc / free with arc

我在Mac OSX的圖像處理應用程序上工作,遇到內存泄漏過多的問題(我正在使用ARC)。 在主窗口中,我有一個滑塊,可以修改像素值並更新圖像。 但是,當我更改滑塊值時,我的應用程序分配了越來越多的內存(“滑動”的數分鍾甚至分配了多達10 GB的內存!)。

應用程序可在相當大的灰度圖像(30-40mb)上運行。 我用像素創建了3個C數組並對其進行操作,但我調用了free但似乎它們沒有被釋放。

更改滑塊的值將觸發該方法:

-(void)changeCurrentMinOrMax
{
    imageProcessQueue = dispatch_queue_create("rwt.tz", NULL);
    dispatch_async(imageProcessQueue, ^{
        // Change display range
        [self setDisplayRangeWithMin:_currentMin andMax:_currentMax];
        // Pack pixels into filtered raw image data
        [self packPixelsIntoFilteredImageData];
        // Create filtered image data
        [self createImage:_rawFilteredImageData];
    });
}

這是被調用方法的實現:

- (void)setDisplayRangeWithMin:(int)min andMax:(int)max
{
    // Calculate number of gray levels
    NSUInteger numberOfGrayLevels = (NSUInteger)pow(2, _bitsPerPixel);
    // Calculate display range
    int range = max - min;
    // Set treshold
    for (unsigned long i = 0; i < numberOFPixels; i++) {
        if (originalPixels[i] < min) {
            pixels[i] = min;
        } else if (originalPixels[i] > max) {
            pixels[i] = max;
        } else {
            pixels[i] = originalPixels[i];
        }
        // map it again into 0-65535 values of gray
        pixels[i] = (UInt16)((numberOfGrayLevels - ZERO_INDEX) * (float)((pixels[i] - min) / (float)range));
    }
}

- (void)packPixelsIntoFilteredImageData
{
    UInt8 *revertedImageDataArray = malloc(sizeOfBitmap);
    unsigned long j = 0;
    for (unsigned long i = 0; i < sizeOfBitmap; i += 2) {
        revertedImageDataArray[i] = (UInt8)((pixels[j] & 0xFF00) >> 8);
        revertedImageDataArray[i+1] = (UInt8)(pixels[j] & 0x00FF);
        j++;
    }

    // pack an array into NSData again
    _rawFilteredImageData = [NSData dataWithBytes:revertedImageDataArray
                                           length:sizeOfBitmap];
    free(revertedImageDataArray);
    revertedImageDataArray = NULL;
}

- (NSImage *)createImage:(NSData *)imgData
{
    _bitsPerComponent = [imgData length] / (_width * _height) * BYTE_SIZE;
    _bitsPerPixel = _bitsPerComponent;
    _bytesPerRow = _width * _bitsPerPixel / BYTE_SIZE;

    CGDataProviderRef provider =
    CGDataProviderCreateWithCFData((CFDataRef)CFBridgingRetain(imgData));
    // which colorspace is better?
    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2);
    //CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGImageRef imageRef = CGImageCreate((size_t)_width,
                                        (size_t)_height,
                                        _bitsPerComponent,
                                        _bitsPerPixel,
                                        _bytesPerRow,
                                        colorSpace,
                                        kCGImageAlphaNone,
                                        provider,
                                        NULL,
                                        false,
                                        kCGRenderingIntentDefault);
    CGColorSpaceRelease(colorSpace);
    CGDataProviderRelease(provider);

    NSSize size = NSMakeSize((CGFloat) _width, (CGFloat)_height);

    dispatch_async(dispatch_get_main_queue(), ^{
        [self willChangeValueForKey:@"image"];
        _image = [[NSImage alloc] initWithCGImage:imageRef
                                             size:size];
        [self didChangeValueForKey:@"image"];
        CGImageRelease(imageRef);
    });
    return _image;
}

我在dealloc中釋放了我的C數組:

- (void)dealloc
{
    // Free memory allocated for C arrays
    if (pixels) {
        free(pixels);
        pixels = NULL;
    }
    if (originalPixels){
        free(originalPixels);
        originalPixels = NULL;
    }
    if (imageDataArray8) {
        free(imageDataArray8);
        imageDataArray8 = NULL;
    }
    // Remove observers
    [self removeObserver:self forKeyPath:@"currentMax"];
    [self removeObserver:self forKeyPath:@"currentMin"];
}

如果我在其他地方使用其他C數組,則會以相同的方法釋放它們。 看起來內存沒有被釋放(即使當我關閉當前圖像並打開新圖像時),並且dealloc被觸發。 你知道發生了什么嗎? 因此,我把頭發扯了!

您有一行代碼說:

CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)CFBridgingRetain(imgData));

不過,根據《 過渡到ARC發行說明》中的“ 管理免費電話橋接”部分,該信息告訴我們:

__bridge_retainedCFBridgingRetain將Objective-C指針強制轉換為Core Foundation指針,並將所有權轉讓給您。 您負責調用CFRelease或相關函數來放棄對象的所有權。

這里根本不需要CFBridgingRetain 而你泄露,因為你永遠不會釋放CFDataRef你傳遞給CGDataProviderCreateWithCFData (松開提供商,而不是CFDataRef )。 您最好還是讓ARC保留所有權並為您清理。 這比將代碼添加到(a)跟蹤通過CFDataRef轉讓所有權的CFBridgingRetain ,然后(b)手動CFRelease CFDataRef來添加代碼容易。 您可以按如下所示更改該行,以完全不轉移所有權,而ARC將負責其余部分(對於NSData而言):

CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)imgData);

無關,但createImage返回的是_image ,它是異步設置的,因此在您擊中該return _image將不會設置_image 您可以解決此問題,使其返回適當的值,但事實證明您沒有使用createImage的返回值,因此將返回類型更改為void可能會更容易。 但是當前代碼只是有些混亂,建議您在實際上不是的時候返回一些東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM