アプリで ImageIO リークが発生する理由を理解するのに多くの時間を費やしました...誰かがこれについて私を助けてくれれば幸いです!
私は2048x1536の画像を持つ多くのUIViewControllerを含むUIPageViewControllerを持っています。最適になるように、UIImage を view.layer.contents に直接設定します。ユーザーが画像間をスワイプすると、bg スレッドに遅延ロードしてからキャッシュします。最大キャッシュ サイズがあるため、ユーザーがスワイプを続けると、ある時点でアプリが画像のアンロードとリロードを開始します。すべて正常に動作しますが、2 ~ 3 サイクルの間非常に速くスワイプし始めると、最終的に CGContextDrawImage を呼び出すときに ImageIO 内でメモリ リークが発生します。漏れは、漏れ計器内では報告されません。なぜこれが起こっているのかよくわかりません。これが私のコードです:
...
Some code here check if there is already a running operation to load imagePath
If so just add the completion block to the completion block list and return
NSBlockOperation* loadImageOperation = [[NSBlockOperation alloc] init];
// Make a weak reference to avoid a retain cycle
__weak NSBlockOperation* weakOp = loadImageOperation;
[loadImageOperation addExecutionBlock: ^{
NSLog(@"Loading img %@",[imagePath lastPathComponent]);
// So this can be executed concurrently several times if the user swipes fast
UIImage* image = [self loadImageFileForCoreAnimation:imagePath];
dispatch_async(dispatch_get_main_queue(), ^{
if (image)
{
[self cacheImage:image withKey:imagePath];
if (completion)
completion(image);
}
else if (!weakOp.isCancelled)
{
NSLog(@"Error loading image %@", imagePath);
}
[self.runningOperationObjects removeObjectForKey:imagePath];
});
}];
...
- (UIImage*)loadImageFileForCoreAnimation:(NSString*)imageFile
{ __weak NSOperation* weakRunningOp = [self getRunningOperationWithImagePath:imageFile];
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename([imageFile UTF8String]);
CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO, kCGRenderingIntentDefault);
if(!image)
image = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, NO, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
if (weakRunningOp.isCancelled)
{
CGImageRelease(image);
return nil;
}
// Here we define the ARGB pixel format
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
size_t bytesPerPixel = 4;
size_t bitsPerComponent = 8;
// bytesPerRow must be at least (width * bytesPerPixel) bytes;
size_t bytesPerRow = width * bytesPerPixel;
// Also : bytesPerRow must be an integer multiple of bytesPerPixel
bytesPerRow = ((bytesPerRow + (bytesPerPixel - 1)) / bytesPerPixel) * bytesPerPixel;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef imageContext = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
if (weakRunningOp.isCancelled)
{
CGImageRelease(image);
CGContextRelease(imageContext);
return nil;
}
// *** This function sometimes leaks!
CGContextDrawImage(imageContext, CGRectMake(0, 0, width, height), image);
CGImageRelease(image);
if (weakRunningOp.isCancelled)
{
CGContextRelease(imageContext);
return nil;
}
CGImageRef outputImage = CGBitmapContextCreateImage(imageContext);
UIImage* bitmapImage = [UIImage imageWithCGImage:outputImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
CGImageRelease(outputImage);
CGContextRelease(imageContext);
return bitmapImage;
}
これが私の楽器のスクリーンショットです。ある時点で VM : ImageIO_PNG_Data が 12mo の割り当てで表示され、消えることはありません。