私は Mac OSX 用の画像処理アプリに取り組んでおり、大量のメモリ リークに問題があります (ARC を使用しています)。メイン ウィンドウには、ピクセルの値を変更して画像を更新するスライダーがあります。しかし、スライダーの値を変更すると、アプリはますます多くのメモリを割り当てます (数分間の「スライド」で最大 10 GB のメモリが割り当てられます!)。
アプリは、グレースケールの非常に大きな画像 (30 ~ 40 MB) で動作します。ピクセルを使用して 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 が発生します。何が起こっているのか分かりますか?そのせいで髪をかきむしる!