0

iPad で OpenGL コンポーネントを含むアプリがクラッシュするという問題が発生しています。アプリはメモリ警告をスローしてクラッシュしますが、それほど多くのメモリを使用していないようです。何か不足していますか?

このアプリは、Vuforia 拡張現実システム (ImageTargets サンプルから大幅に借用) に基づいています。アプリに含める必要がある約 40 の異なるモデルがあるため、メモリを節約するために、必要に応じてアプリにオブジェクトを動的にロード (およびテクスチャなどをレンダリング) しています。UIScrollView の遅延読み込みのアイデアをコピーしようとしました。3 つの 4 MB の割り当ては、ユーザーが表示する別のモデルを選択したときに備えて、メモリに読み込んだテクスチャです。

ここで何か変ですか?

器具 - 漏れ

私は OpenGL についてはまったく知りません (Vurforia エンジンを選択した理由の 1 つです)。以下のスクリーン ショットで気になる点はありますか? Vurforia の ImageTagets サンプル アプリにも初期化されていないテクスチャ データ (フレームごとに約 1 つ) があることに注意してください。これは問題ではないと思います。

インストルメント - OpenGL ES アナライザー

どんな助けでも大歓迎です!!

3D オブジェクトを生成するコードは次のとおりです (EAGLView 内):

// Load the textures for use by OpenGL
-(void)loadATexture:(int)texNumber {

if (texNumber >= 0 && texNumber < [tempTextureList count]) {
    currentlyChangingTextures = YES;

    [textureList removeAllObjects];
    [textureList addObject:[tempTextureList objectAtIndex:texNumber]];

    Texture *tex = [[Texture alloc] init];
    NSString *file = [textureList objectAtIndex:0];

    [tex loadImage:file];



    [textures replaceObjectAtIndex:texNumber withObject:tex];
    [tex release];

    // Remove all old textures outside of the one we're interested in and the two on either side of the picker.
    for (int i = 0; i < [textures count]; ++i) {

        if (i < targetIndex - 1 || i > targetIndex + 1) {
            [textures replaceObjectAtIndex:i withObject:@""];
        }
    }


    // Render - Generate the OpenGL texture objects
    GLuint nID;
    Texture *texture = [textures objectAtIndex:texNumber];
    glGenTextures(1, &nID);
    [texture setTextureID: nID];
    glBindTexture(GL_TEXTURE_2D, nID);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, [texture width], [texture height], 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)[texture pngData]);


    // Set up objects using the above textures.
    Object3D *obj3D = [[Object3D alloc] init];

    obj3D.numVertices = rugNumVerts;
    obj3D.vertices = rugVerts;
    obj3D.normals = rugNormals;
    obj3D.texCoords = rugTexCoords;

    obj3D.texture = [textures objectAtIndex:texNumber];

    [objects3D replaceObjectAtIndex:texNumber withObject:obj3D];
    [obj3D release];

    // Remove all objects except the one currently visible and the ones on either side of the picker.
    for (int i = 0; i < [tempTextureList count]; ++i) {

        if (i < targetIndex - 1 || i > targetIndex + 1) {
            Object3D *obj3D = [[Object3D alloc] init];
            [objects3D replaceObjectAtIndex:i withObject:obj3D];
            [obj3D release];
        }
    }


    if (QCAR::GL_20 & qUtils.QCARFlags) {
        [self initShaders];
    }


    currentlyChangingTextures = NO;
}

}

textures オブジェクトのコードは次のとおりです。

- (id)init
{
self = [super init];
pngData = NULL;

return self;
}


- (BOOL)loadImage:(NSString*)filename
{
BOOL ret = NO;

// Build the full path of the image file
NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
NSString* fullPath = [resourcePath stringByAppendingPathComponent:filename];

// Create a UIImage with the contents of the file
UIImage* uiImage = [UIImage imageWithContentsOfFile:fullPath];

if (uiImage) {
    // Get the inner CGImage from the UIImage wrapper
    CGImageRef cgImage = uiImage.CGImage;

    // Get the image size
    width = CGImageGetWidth(cgImage);
    height = CGImageGetHeight(cgImage);

    // Record the number of channels
    channels = CGImageGetBitsPerPixel(cgImage)/CGImageGetBitsPerComponent(cgImage);

    // Generate a CFData object from the CGImage object (a CFData object represents an area of memory)
    CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));

    // Copy the image data for use by Open GL
    ret = [self copyImageDataForOpenGL: imageData];
    CFRelease(imageData);
}

return ret;
}


- (void)dealloc
{
if (pngData) {
    delete[] pngData;
}

[super dealloc];
}

@end


@implementation Texture (TexturePrivateMethods)

- (BOOL)copyImageDataForOpenGL:(CFDataRef)imageData
{    
if (pngData) {
    delete[] pngData;
}

pngData = new unsigned char[width * height * channels];
const int rowSize = width * channels;
const unsigned char* pixels = (unsigned char*)CFDataGetBytePtr(imageData);

// Copy the row data from bottom to top
for (int i = 0; i < height; ++i) {
    memcpy(pngData + rowSize * i, pixels + rowSize * (height - 1 - i), width * channels);
}

return YES;
}
4

2 に答える 2

2

おそらく、アプリケーションの実際のメモリ使用量は表示されていません。この回答で説明したように、割り当てインストルメントは OpenGL ES からメモリ使用量を隠しているため、アプリケーションのサイズを測定するために使用することはできません。代わりに、Memory Monitor インストゥルメントを使用してください。これにより、アプリケーションが思っているよりもはるかに多くの RAM を使用していることがわかります。これは、Instruments を使用して iOS で OpenGL ES を最適化しようとするときに遭遇する一般的な問題です。

どのオブジェクトまたはリソースがメモリに蓄積されている可能性があるか心配な場合は、Allocations インストルメントのヒープ ショット機能を使用して、アプリケーション内で繰り返しタスクを実行するときに、割り当てられているが削除されていない特定のリソースを特定できます。それが、適切に削除されていないテクスチャやその他のアイテムを追跡した方法です.

于 2012-06-08T14:49:37.187 に答える
1

いくつかのコードを見ると役立つでしょうが、私はいくつかの推測をすることができます:

アプリに含める必要がある約 40 の異なるモデルがあるため、メモリを節約するために、必要に応じてオブジェクトをアプリに動的に読み込みます (およびテクスチャなどをレンダリングします)。UIScrollView の遅延読み込みのアイデアをコピーしようとしました。3 つの 4 MB の割り当ては、ユーザーが表示する別のモデルを選択したときに備えて、メモリに読み込んだテクスチャです。(...)

この種のアプローチは理想的ではありません。メモリが適切に割り当て解除されていない場合、それが問題の原因である可能性が最も高いです。適切な予防策を講じないと、最終的にメモリが不足し、プロセスが停止します。使用されているエンジンにメモリ リークがあり、アクセス スキームによって公開されている可能性が非常に高いです。

今日のオペレーティング システムは、RAM とストレージを区別していません。彼らにとって、それはすべて単なるメモリであり、すべてのアドレス空間はとにかくブロックストレージシステムによって支えられています (実際に接続されているストレージデバイスがあるかどうかは問題ではありません)。

モデルをメモリに読み込む代わりに、モデルをメモリ マップ (mmap) する必要があります。これにより、OS に「ストレージのこの部分はアドレス空間で見えるようにする必要があります」と通知され、OS カーネルは必要なすべての転送を必要なときに実行します。

Vurforia の ImageTagets サンプル アプリにも初期化されていないテクスチャ データ (フレームごとに約 1 つ) があることに注意してください。これは問題ではないと思います。

これは、OpenGL テクスチャ オブジェクトが適切に削除されていないことを示す強力な指標です。

どんな助けでも大歓迎です!!

私のアドバイス: 1970 年代のようなプログラミングはやめましょう。今日のコンピューターとオペレーティング システムの動作は異なります。http://www.varnish-cache.org/trac/wiki/ArchitectNotesも参照してください。

于 2012-06-08T07:44:09.423 に答える