2015-09-11 51 views
6

私はこの動作をiOS 9でしか観察していません。 iOS 8は正常に動作します。なぜCIContext.createCGImageはメモリリークの原因ですか?

これはSDKのバグである可能性があります。私はAppleにレーダーを公開していますが(22644754)、とても奇妙なことに気づき、漏れを避ける。

私が観察したことは、CIContext.createCGImageが呼び出されるたびにメモリ使用量が増加することです。難しい部分は、メモリの増加がアプリの外で発生するということです。

「メモリレポート」をXcodeから見ると、「その他のプロセス」セクションにメモリが表示されます。

まず、私はEAGLContextに裏打ちされたCIContextを作成します:

基本的に、私は問題は以下の通りです引き起こすことが何をすべきか(私は厳密に必要な部品がリークを再現するためのコードを簡素化している)

let glContext = EAGLContext(API: .OpenGLES2)! 
let ciContext = CIContext(EAGLContext: glContext, options: [kCIContextOutputColorSpace : NSNull()]) 

はその後、私は以下を使用して画像を描画:

let input = CIImage(image: UIImage(named: "DummyImage")!)! 
ciContext.createCGImage(input, fromRect: input.extent) 

DummyImageはちょうどサンプル画像ファイルです。リークはこの画像のサイズに直接関連しているので、問題をより顕著にするために大きな画像を使用するのが最善です。

私はCIFilterを使用していないので(同じ結果をもたらす)、結果の画像をキャプチャしていません(キャプチャしてもCGImageReleaseをオブジェクトとして使用できませんでした自動的に管理されます)。

レンダリングコードが十分に実行された場合、メモリが非常に大きくなり、実行中のアプリケーションが強制終了されます。

興味深いことに、CIContextを破壊しても差は出ませんが、EAGLContextを破棄すると撮影されたメモリが返されます。これは、OpenGL側でリークが起こっていると私に思い出させます。

リークを引き起こす可能性のあるコードに何かがないのですか? EAGLContextのメモリを解放するために私ができる呼び出しはありますか? (費用のかかる操作であるため、常に再作成することは選択肢ではありません)。


問題を再現するための簡単なプロジェクトを作成しました。

  1. オープンし、デバイス上の添付プロジェクトを実行します。再現する

    https://www.dropbox.com/s/zm19u8rmujv6jet/EAGLContextLeakDemo.zip?dl=0

    手順は次のとおりです。あなたはでそれを見つけることができます。

  2. Xcodeの「メモリレポート」画面に従います。成長は「利用状況比較」の円グラフの「その他のプロセス」の部分に表示されます。
  3. アプリには3つのボタンがあります。それぞれはcreateCGImageコマンドを特定の回数実行します(ボタンラベルに表示されています)。
  4. いずれかのボタンをタップすると、「その他のプロセス」のメモリ使用量が増加します。これは、いくつかのcreateCGImage呼び出しを実行した後でより顕著になるかもしれません。
  5. 100レンダリングボタンをタップすると効果がより明確に表示されます。
  6. メモリが過剰になると、アプリケーションがクラッシュします。

答えて

0

この問題は、コードが掲載iOSの9.1ベータ版に3

を開始解決されているiOSの9のバグとして確認されています元の質問では正しいです。 iOS 9以前のバージョンやiOS 9.1 Beta 3以降のバージョンでのリークを防ぐために必要な変更はありません。

1

私が解決した方法は、コンテキストをバッファにレンダリングし、それをJPGとしてファイルに書き込むことでした。古い世代のiOSデバイスでこのフローを最適化する方法はさらに詳しく調べる必要がありますが、createCGImageと比較してうまくいくようです。このコードは、CIImageをJPEGまたはビットマップNSDataに変換する場合にも便利です。完全なサンプルコードはここで見ることができます:

https://github.com/mmackh/IPDFCameraViewController

static CIContext *ctx = nil; 

if (!ctx) 
{ 
    ctx = [CIContext contextWithOptions:@{kCIContextWorkingColorSpace:[NSNull null]}]; 
} 

CGSize bounds = enhancedImage.extent.size; 
int bytesPerPixel = 8; 
uint rowBytes = bytesPerPixel * bounds.width; 
uint totalBytes = rowBytes * bounds.height; 
uint8_t *byteBuffer = malloc(totalBytes); 

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

[ctx render:enhancedImage toBitmap:byteBuffer rowBytes:rowBytes bounds:enhancedImage.extent format:kCIFormatRGBA8 colorSpace:colorSpace]; 

CGContextRef bitmapContext = CGBitmapContextCreate(byteBuffer,bounds.width,bounds.height,bytesPerPixel,rowBytes,colorSpace,kCGImageAlphaNoneSkipLast); 

CGImageRef imgRef = CGBitmapContextCreateImage(bitmapContext); 

CGColorSpaceRelease(colorSpace); 
CGContextRelease(bitmapContext); 
free(byteBuffer); 

if (imgRef == NULL) { goto release; } 


CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:filePath]; 
CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypeJPEG, 1, NULL); 
CGImageDestinationAddImage(destination, imgRef, nil); 
CGImageDestinationFinalize(destination); 
CFRelease(destination); 

success = YES; 

goto release; 

release : 
{ 
    CFRelease(imgRef); 

    if (success) 
    { 
     //completionHandler(filePath); 
    } 

    dispatch_resume(_captureQueue); 
} 
+0

なぜ 'bytesPerPixel = 8'ですか? 'kCIFormatRGBA8'はピクセル形式で4バイトではありませんか? –

関連する問題