8

アプリのメモリが不足しています。これを解決するために、フレームバッファーを画像に書き込む関数で使用されている 2 つの非常に大きな配列を解放します。メソッドは次のようになります。

-(UIImage *) glToUIImage {
    NSInteger myDataLength = 768 * 1024 * 4;
    // allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, 768, 1024, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    // gl renders "upside down" so swap top to bottom into new array.
    // there's gotta be a better way, but this works.
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    for(int y = 0; y <1024; y++)
    {
            for(int x = 0; x <768 * 4; x++)
            {
                    buffer2[(1023 - y) * 768 * 4 + x] = buffer[y * 4 * 768 + x];
            }
    }

     // make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);

    // prep the ingredients
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * 768;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    // make the cgimage
    CGImageRef imageRef = CGImageCreate(768, 1024, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

    // then make the uiimage from that
    UIImage *myImage = [UIImage imageWithCGImage:imageRef];

    //free(buffer);
    //free(buffer2);

    return myImage;
}

最後に free(buffer) と free(buffer2) の 2 つが呼び出されていることに注意してください。これらは iPad シミュレーターで問題なく動作し、メモリの問題を取り除き、無礼に生成できるようにします。ただし、iPad は即座に殺されます。同様に、初めて実行します。free() 呼び出しを削除すると、問題なく実行されますが、1、2 分後にメモリが不足します。では、なぜ free() 呼び出しがデバイスをクラッシュさせるのでしょうか?

注 - デバイスを明示的にクラッシュさせるのは free() の呼び出しではなく、後でクラッシュします。しかし、それが根本的な原因のようです/..

編集 - 誰かが正確にクラッシュする場所について尋ねられました。このフローは、画像を別のオブジェクトに返し、ファイルに書き込みます。「UIImageJPEGRepresentation」メソッドを呼び出すと、EXT_BAD_ACCESS メッセージが生成されます。これは、ファイルに書き込むために渡す UIImage が破損しているか、null であるか、または他の何かであることが原因であると想定しています。しかし、これは、これら 2 つのバッファーを解放したときにのみ発生します。

メモリが何らかの形で UIIMage に関連しているかどうかは理解できますが、特にシミュレータで動作するため、実際にはそうすべきではありません。iPadが「無料」通話を処理する方法にかかっているのではないかと思いました...

4

3 に答える 3

8

docsを読むと、 CGDataProviderCreateWithData は buffer2 が指すメモリのみを参照し、コピーはしないと思います。イメージがリリースされるまで、割り当てたままにしておく必要があります。

これを試して:

static void _glToUIImageRelease (void *info, const void *data, size_t サイズ) {
    無料(データ);
}

-(UIImage *) glToUIImage {
    NSInteger myDataLength = 768 * 1024 * 4;
    // 配列を割り当ててピクセルを読み込みます。
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, 768, 1024, GL_RGBA, GL_UNSIGNED_BYTE, バッファ);

    // gl は「上下逆さま」にレンダリングするので、上から下を新しい配列に入れ替えます。
    // もっと良い方法があるはずですが、これでうまくいきます。
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    for(int y = 0; y
于 2010-07-23T12:03:44.010 に答える
1

まず最初に、mallocが失敗して返されたかどうかを実際に確認する必要がありますNULL。ただし、それでも問題が解決しない場合は、デバッガーを使用してプログラムをステップ実行し、失敗した場所を正確に確認します(または、少なくともスタックトレースを取得します)。私の経験から、予期しない領域のどこかでクラッシュするなどの奇妙な障害は、ほとんどの場合、バッファオーバーフローによって、以前の任意のデータが破損することです。

于 2010-07-23T11:50:15.130 に答える
0

バッファーのサイズが小さすぎますか? ループを見てください。

for(int y = 0; y <1024; y++)
{
     for(int x = 0; x <768 * 4; x++)
     {
          buffer2[(1023 - y) * 768 * 4 + x] = buffer[y * 4 * 768 + x];
     }
}

y == 0 および x == (768*4)-1 とすると、buffer2 のインデックスは割り当てられたサイズを超えています。たぶんその前に圏外?

于 2010-07-23T17:32:24.490 に答える