1

生データをファイルストレージ用のUIImageオブジェクトに変換するためのテスト関数であるコードイテレータがあります。2つの失敗パスまたはオプションがあります。私は失敗する可能性があります:

A.)リークがあることによって(機器はそれを示していません-機器はすべての割り当てが安定しているようです、私は何度も繰り返す必要があり、50と言うと、機器または通常のテスト機能の実行でクラッシュします)。以下の「b」オプションにより、メモリが原因のようです。

B.)UIImage内でCGオブジェクトの強制リリースを実行できます。その場合、アプリは続行します。イテレータが完了すると、サブ関数から返された画像の下にあるCGImageを解放しようとすると、最後の反復でテストがクラッシュします。イテレータは、要求した反復回数に関係なく、実行を完了します。これは、私がリークを修正したという事実を示しています。だから今、私は最後の反復について何が特別なのかを一緒にパズルしようとしていますか?(アーク?)

- (UIImage *) convertRGBToUIImage:(unsigned char *) buffer 
                            withWidth:(int) width
                           withHeight:(int) height 
{

   CGColorSpaceRef colorSpace       = nil;
   CGContextRef    context          = nil;
   CGImageRef      ref              = nil;
   UIImage        *retImg           = nil;

   colorSpace = CGColorSpaceCreateDeviceRGB();
   if (colorSpace == NULL)
   {
      NSLog(@"ERROR: allocating color space convert Bitmap\n");
      return nil;
   }

   context = CGBitmapContextCreate (buffer, width, height, 8, width * 4, colorSpace,     kCGImageAlphaPremultipliedLast);
   CGColorSpaceRelease(colorSpace );

   if (context == NULL)
   {
     NSLog(@"ERROR: Context not created!");
     return nil;
   }

   ref = CGBitmapContextCreateImage(context);                                     
   CGContextRelease(context);

   retImg = [UIImage imageWithCGImage:ref];
   CGImageRelease(ref);

   return retImg;
}

イテレータの基本

for(int i = 0; i < numberiterations; i++)
{ 
    UIImage *completedImage = [phelper convertRGBToUIImage:pBuffer withWidth:width withHeight:height]

    //...save it out or display it

    //Turn on one of the scenarios below

    //scenario "A" -- will leak memory (instruments doesn't seem to turn anything up)
    //ARC free
    //completedImage = nil; //this will leak and fail after ~50 iterations

    //-or-

    //scenario "B" -- will crash on the very last iteration every time but can run x times
    //CGImageRelease([completedImage CGImage];


}

Xcodeの分析ツールは、上記のシナリオ「A」を優先します。繰り返しますが、これを行うことができ、すべてが素晴らしいように見えますが、テストを正常に完了できません。これはARCを指していると思います。__bridge型のキャストを理解しようとしましたが、成功しませんでした。私は構文を正しく理解できないようで、おそらくそれは私の問題に対する答えではありません。ヒントやアイデアをいただければ幸いです。

4

1 に答える 1

3

Instrumentsがリークを示さない理由は、技術的には、何もないからです

あなたが見ているのは、@autoreleasepool十分にタイトではない からのメモリ プレッシャです。

メソッドconvertRGBToUIImage:withWidth:withHeight:は新しい自動解放された画像を返しますが、最も近い@autoreleasepoolものはループの外にあります。

つまり、ループが存在するメソッドが戻るまで、これらの画像はすべて破棄されません。

これが、シナリオ A で反復ごとにメモリ消費量が増加し、シナリオ B でループ後にアプリケーションがクラッシュする理由です。

UIImageは、ほとんどの場合、Objective-C のラッパーであり、シナリオ BCGImageRefの追加機能がバッキング ストアを足元CGImageReleaseから引き出します。UIImageこのバッキング ストアはたまたま のメモリを大量に消費する部分であるUIImageため、メモリ消費量の大幅な増加はほとんどなくなります。

ループが返されたメソッドの後にが@autoreleasepool排出UIImageれると、すべての一時インスタンスが破棄されます。これらの一時インスタンスは、バッキングを破棄する必要がありCGImageRefます...そして、プログラムがブームになります。

トリックは@autoreleasepool、ループ内で独自のものを作成することです。

for (int i = 0; i < numberiterations; i++) {
    @autoreleasepool {
        // your old iteration body comes here
    }
}

これで、シナリオ A は期待どおりに動作し、シナリオ B は最初の反復の最後にすぐにクラッシュします。これも当然のことです。


そして今、いくつかの深刻な脳f ** kについて:

元のコードを「リリース」方式で ARC の下で実行すると (つまり、-Os「最速最小」コンパイラ フラグを使用して)、シナリオ Aでクラッシュする可能性はほとんどなくなります。

この一見奇妙な動作の理由は、実際のメモリ管理を実行する C 関数の特別なセットを ARC がコードに追加するためです。これらの関数は一定であるため (Objective-C のメソッド呼び出しは必ずしもそうではありません)、コンパイラそれらの特定の組み合わせを最適化できます。

これによりUIImage、最初から が autorelease-pool に挿入されないため、ループの各反復後に破棄されます。

于 2012-05-19T14:00:25.063 に答える