[英]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_retained
或CFBridgingRetain
将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.