2012-05-10 2 views
0

Мой IPad приложение, которое я создаю должен быть в состоянии создать плитки для более 4096x2992 изображение, которое генерируется в начале моего приложения ..Large Image Processing (ARC) Основные утечки памяти

4096x2992 изображение не очень сложный (что я тестирую), и когда он записывается в файл в формате png, составляет приблизительно 600kb ...

В симуляторе этот код работает нормально, однако, когда я запускаю приложение в более жестких условиях памяти (на моем iPad), процесс завершается, потому что у него закончилась память ...

Я уже использовал тот же код в приложении, который работал нормально (был только c повторные плитки для изображений 3072x2244, однако) ...

Либо я должен делать что-то глупое, или мой @ autoreleasepool не работает так, как должен (я думаю, что я упомянул, что im использует ARC) ... При работе в инструментах Я могу просто увидеть, что используемая память поднимается вверх до ~ 500 мб, где она падает!

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

Просто немного историю о том, как моя функция вызывается, чтобы вы знали, что происходит ... Приложение использует CoreGraphics для рендеринга UIView (4096x2992) с некоторым UIImageView внутри него, затем отправляет эту ссылку UIImage в мою функцию buildFromImage: (ниже), где начинается резка/изменение размера изображения для создания файла ...

Вот код buildFromImage: ... проблемы с памятью создаются из основного цикла под NSLog(@"LOG ------------> Begin tile loop "); ...

-(void)buildFromImage:(UIImage *)__image { 

NSLog(@"LOG ------------> Begin Build "); 



//if the __image is over 4096 width of 2992 height then we must resize it! (stop crashes ect) 
if (__image.size.width > __image.size.height) { 
    if (__image.size.width > 4096) { 
     __image = [self resizeImage:__image toSize:CGSizeMake(4096, (__image.size.height * 4096/__image.size.width))]; 
    } 
} else { 
    if (__image.size.height > 2992) { 
     __image = [self resizeImage:__image toSize:CGSizeMake((__image.size.width * 2992/__image.size.height), 2992)]; 
    } 
} 

//create preview image (if landscape, no more than 748 high... if portrait, no more than 1004 high) must keep scale 
NSString *temp_archive_store = [[NSString alloc] initWithFormat:@"%@/%i-temp_imgdat.zip",NSTemporaryDirectory(),arc4random()]; 
NSString *temp_tile_store = [[NSString alloc] initWithFormat:@"%@/%i-temp_tilestore/",NSTemporaryDirectory(),arc4random()]; 


//create the temp dir for the tile store 
[[NSFileManager defaultManager] createDirectoryAtPath:temp_tile_store withIntermediateDirectories:YES attributes:nil error:nil]; 

//create each tile and add it to the compressor once its made 
//size of tile 
CGSize tile_size = CGSizeMake(256, 256); 
//the scales that we will be generating the tiles too 
NSMutableArray *scales = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:1000],[NSNumber numberWithInt:500],[NSNumber numberWithInt:250],[NSNumber numberWithInt:125], nil]; //scales to loop round over 

NSLog(@"LOG ------------> Begin tile loop "); 
@autoreleasepool { 
    //loop through the scales 
    for (NSNumber *scale in scales) { 

     //scale the image 
     UIImage *imageForScale = [self resizedImage:__image scale:[scale intValue]]; 

     //calculate number of rows... 
     float rows = ceil(imageForScale.size.height/tile_size.height); 

     //calulate number of collumns 
     float cols = ceil(imageForScale.size.width/tile_size.width); 

     //loop through rows and cols 

     for (int row = 0; row < rows; row++) { 

      for (int col = 0; col < cols; col++) { 

       NSLog(@"LOG ------> Creating Tile (%i,%i,%i)",col,row,[scale intValue]); 

       //build name for tile... 
       NSString *tile_name = [NSString stringWithFormat:@"%@_%i_%i_%i.png",@"image",[scale intValue],col,row]; 

       @autoreleasepool { 

        //build tile for this coordinate 
        UIImage *tile = [self tileForRow:row column:col size:tile_size image:imageForScale]; 

        //convert image to png data 
        NSData *tile_data = UIImagePNGRepresentation(tile); 

        [tile_data writeToFile:[NSString stringWithFormat:@"%@%@",temp_tile_store,tile_name] atomically:YES]; 

       } 


      } 

     } 

    } 

} 
}   

Вот мои изменения размера/обрезки функции тоже, поскольку они также могут быть причиной проблемы ..

-(UIImage *)resizeImage:(UIImage *)inImage toSize:(CGSize)scale { 

@autoreleasepool { 

    CGImageRef inImageRef = [inImage CGImage]; 

    CGColorSpaceRef clrRf = CGColorSpaceCreateDeviceRGB(); 

    CGContextRef ctx = CGBitmapContextCreate(NULL, ceil(scale.width), ceil(scale.height), CGImageGetBitsPerComponent(inImageRef), CGImageGetBitsPerPixel(inImageRef)*ceil(scale.width), clrRf, kCGImageAlphaPremultipliedFirst); 

    CGColorSpaceRelease(clrRf); 

    CGContextDrawImage(ctx, CGRectMake(0, 0, scale.width, scale.height), inImageRef); 

    CGImageRef img = CGBitmapContextCreateImage(ctx); 

    UIImage *image = [[UIImage alloc] initWithCGImage:img scale:1 orientation:UIImageOrientationUp]; 

    CGImageRelease(img); 
    CGContextRelease(ctx); 

    return image; 

} 

} 

- (UIImage *)tileForRow: (int)row column: (int)col size: (CGSize)tileSize image: (UIImage*)inImage 
{ 

@autoreleasepool { 

    //get the selected tile 
    CGRect subRect = CGRectMake(col*tileSize.width, row * tileSize.height, tileSize.width, tileSize.height); 

    CGImageRef inImageRef = [inImage CGImage]; 

    CGImageRef tiledImage = CGImageCreateWithImageInRect(inImageRef, subRect); 

    UIImage *tileImage = [[UIImage alloc] initWithCGImage:tiledImage scale:1 orientation:UIImageOrientationUp]; 

    CGImageRelease(tiledImage); 

    return tileImage; 

} 

} 

Теперь я никогда не использую, чтобы быть хорошим, что с управлением памятью, так что я потратил время, чтобы прочитать его, а также преобразовал мой проект в ARC, чтобы узнать, может ли это решить мои проблемы (это было давно), но из результатов, которые я получаю после профилирования его в инструментах, я должен делать что-то НЕПОСРЕДСТВЕННО неправильно для память течет так же плохо, как и она, но я просто не вижу, что я делаю неправильно.

Если кто-нибудь может указать на что-нибудь, что я могу делать неправильно, было бы здорово!

Благодаря

Лиам

(дайте мне знать, если вам нужно больше информации)

+3

4096 * 2992 * 4 (RGBA) дает изображение вокруг 40Мб. Обработка, конечно, требует входного и выходного буфера ... это тонна памяти! – bbum

+0

Ahh Я вижу, что мне, возможно, придется изучить другие способы сделать это. – liamnichols

+0

Что находится в реализации метода resizedImage: scale :? Кроме того, создайте пул автозапуска внутри цикла for. –

ответ

0

Я использую "UIImage + Изменить размер". Внутри @autoreleasepool {} он отлично работает с ARC в цикле.

https://github.com/AliSoftware/UIImage-Resize

-(void)compress:(NSString *)fullPathToFile { 
@autoreleasepool { 
    UIImage *fullImage = [[UIImage alloc] initWithContentsOfFile:fullPathToFile]; 
    UIImage *compressedImage = [fullImage resizedImageByHeight:1024]; 
    NSData *compressedData = UIImageJPEGRepresentation(compressedImage, 75.0); 
    [compressedData writeToFile:fullPathToFile atomically:NO]; 
} 

}

Смежные вопросы