Вопрос по opengl-es, crash, memory, ios – Сбой при запуске OpenGL на iOS после предупреждения памяти

0

У меня проблемы с приложением, в котором компонент OpenGL падает на iPad. Приложение выдает предупреждение о сбое памяти и вылетает, но, похоже, оно не использует столько памяти. Я что-то пропустил?

Приложение основано на системе дополненной реальности Vuforia (заимствовано из образца ImageTargets). У меня есть около 40 различных моделей, которые нужно включить в мое приложение, поэтому в целях сохранения памяти я динамически загружаю объекты (и рендеринг текстур и т. Д.) В приложение по мере необходимости. Я попытался скопировать идею ленивой загрузки UIScrollView. Три выделения по 4 Мб - это текстуры, которые я загрузил в память, к которым пользователь готов выбрать другую модель для отображения.

Что-нибудь странное здесь?

Instruments - leaks

Я совсем мало знаю об OpenGL (одна из причин, по которой я выбрал движок Vurforia). Что-нибудь на этом снимке экрана ниже, что должно беспокоить меня? Обратите внимание, что в образце приложения Vurforia ImageTagets также есть неинициализированные данные текстуры (примерно по одному на кадр), поэтому я не думаю, что это проблема.

Instruments - OpenGL ES analyzer

Любая помощь будет оценена !!

Вот код, который генерирует трехмерные объекты (в 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;
}

}

Вот код в объекте текстур.

- (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;
}

Ваш Ответ

2   ответа
2

Скорее всего, вы не видите истинного использования памяти вашим приложением. Как я объясняю вэтот ответинструмент Allocations скрывает использование памяти от OpenGL ES, поэтому вы не можете использовать его для измерения размера вашего приложения. Вместо этого используйте инструмент Memory Monitor, который, я уверен, покажет, что ваше приложение использует гораздо больше оперативной памяти, чем вы думаете. Это общая проблема, с которой люди сталкиваются, когда пытаются оптимизировать OpenGL ES на iOS с помощью Instruments.

Если вы обеспокоены тем, какие объекты или ресурсы могут накапливаться в памяти, вы можете использовать функциональность «кучные снимки» инструмента «Распределение» для определения конкретных ресурсов, которые выделены, но никогда не удаляются при выполнении повторяющихся задач в вашем приложении. Вот как я отслеживал текстуры и другие элементы, которые не были должным образом удалены.

Спасибо за это. Метод dealloc в Textures.mm пришлось изменить, чтобы правильно удалить текстуру. That Guy
1

Просмотр некоторого кода помог бы, но я могу сделать некоторые уловки:

I have about 40 different models I need to include in my app, so in the interests of memory conservation I am loading the objects (and rendering textures etc) dynamically in the app as I need them. I tried to copy the UIScrollView lazy loading idea. The three 4mb allocations are the textures I have loaded into memory ready for when the user selects a different model to display. (...)

Такой подход не идеален; и это, скорее всего, причина ваших проблем, если память не освобождена должным образом. В конце концов вам не хватит памяти, и тогда ваш процесс умрет, если вы не примете надлежащие меры предосторожности. Весьма вероятно, что в используемом движке произошла утечка памяти, обнаруженная вашей схемой доступа.

Сегодня операционные системы не различают ОЗУ и хранилище. Для них это все просто память и все адресное пространство в любом случае поддерживается системой блочного хранилища (если на самом деле какое-то подключенное устройство хранения данных не имеет значения).

Итак, что вы должны сделать: вместоread- вставляя свои модели в память, вы должны отобразить их в памяти (mmap). Это говорит ОС «эта часть хранилища должна быть видимой в адресном пространстве» и ядро ОС выполнит все необходимые передачи в установленный срок.

Note that Vurforia's ImageTagets sample app also has Uninitialized Texture Data (about one per frame), so I don't think this is the problem.

Это сильный показатель того, что объекты текстуры OpenGL не удаляются должным образом.

Any help would be appreciated!!

Мой совет: прекратите программировать, как это было в 1970-х годах. Современные компьютеры и операционные системы работают по-разному. Смотрите такжеhttp://www.varnish-cache.org/trac/wiki/ArchitectNotes

Спасибо за ваш вклад. Пища для размышлений! That Guy

Похожие вопросы