2010-07-23 14 views
8

Mi aplicación se está quedando sin memoria. Para resolver esto, libero dos matrices muy grandes usadas en una función que escribe un framebuffer en una imagen. El método es el siguiente:free() llamada funciona en el simulador, enoja al iPad. iPad smash

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

Nota los dos llamados a libre (buffer) y libre (tampón 2) al final hay? Esos funcionan bien en el simulador de iPad, eliminando el problema de memoria y permitiéndome generar con imprudencia. Sin embargo, matan el iPad al instante. Al igual que la primera vez que lo ejecuta. Si elimino las llamadas gratuitas() funciona bien, simplemente se queda sin memoria después de uno o dos minutos. Entonces, ¿por qué la llamada gratuita() bloquea el dispositivo?

Nota: no es la llamada a free() que bloquea explícitamente el dispositivo, se bloquea más tarde. Pero esa parece ser la causa raíz/..

EDITAR - Alguien pregunta dónde se bloquea exactamente. Este flujo continúa para devolver la imagen a otro objeto, que lo escribe en un archivo. Al llamar al método 'UIImageJPEGRepresentation', genera un mensaje EXT_BAD_ACCESS. Supongo que esto es porque el UIImage que estoy pasando para escribir en el archivo está dañado, nulo o algo más. Pero esto solo sucede cuando libero esos dos buffers.

Entiendo si la memoria estaba de alguna manera relacionada con el UIIMage, pero realmente no debería ser así, especialmente porque funciona en el simulador. Me preguntaba si se debe a que iPad maneja las llamadas "gratuitas" ...

Respuesta

8

De la lectura de la docs, creo CGDataProviderCreateWithData será única referencia la memoria apuntada por buffer2, no copiarlo. Debe mantenerlo asignado hasta que se libere la imagen.

Prueba esto:

 
static void _glToUIImageRelease (void *info, const void *data, size_t size) { 
    free(data); 
} 

-(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
+0

¡Acabo de sacar eso también! Excelente lugar, mi buen hombre. ¡Gracias! :) – mtrc

1

Lo primero es lo primero, realmente debería verificar si malloc falló y devolvió NULL. Sin embargo, si eso no resuelve su problema, use un depurador y recorra su programa para ver exactamente dónde falla (o al menos para obtener un seguimiento de la pila). Desde mi experiencia, las fallas extrañas como estrellarse en algún lugar en áreas insospechadas casi siempre son desbordamientos de búfer que corrompen datos arbitrarios algún tiempo antes.

+0

Sé dónde falla (más o menos) pero el rastro es bastante largo. Lo editaré ahora. – mtrc

+0

Puede tener razón sobre el desbordamiento. Si no libero buffer2, funciona bien. Incluso si libero el buffer. – mtrc

0

Buffer (s) son de tamaño insuficiente? Mira los bucles.

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

let y == 0 y x == tamaño (768 * 4) -1, el índice de buffer2 exceda asignado. Probablemente fuera del rango antes de eso?

Cuestiones relacionadas