2013-08-28 7 views
0

Хорошо, поэтому я загружаю кучу крупно-ичных изображений (5 МБ) с сервера на куски, затем сшивая фрагменты и рендеринг общего изображения из массива байтов. Тем не менее, я понял, что данные для каждого изображения не выпускаются и, следовательно, накапливаются, вызывая предупреждение о памяти и крах моего приложения. Я думал, что из-за моего явного (__bridge_transfer NSData *) каста, который ARC позаботится о выпуске объекта, но он все еще является проблемой. В инструментах объекты, называемые «CGDataProviderCopyData» размером ~ 1mb, не отбрасываются для каждого файла, который сшивается во все изображение. Любые идеи или кто-нибудь, кто может направить меня в правильном направлении? Весьма признателен.CGDataProviderCopyData накапливается в памяти, вызывая сбои.

// Create array to add all files into total image 
NSMutableArray *byteArray = [[NSMutableArray alloc] initWithCapacity:(imageHeight * imageWidth)]; 

// Iterate through each file in files array 
for (NSString *file in array) 
{   
    // Set baseURL for individual file path 
    NSString *baseURL = [NSString stringWithFormat:@"http://xx.225.xxx.xxx%@",[imageInfo objectForKey:@"BaseURL"]]; 

    // Specify imagePath by appending baseURL to file name 
    NSString *imagePath = [NSString stringWithFormat:@"%@%@", baseURL, file]; 

    // Change NSString --> NSURL --> NSData 
    NSURL *imageUrl = [NSURL URLWithString:imagePath]; 
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl]; 

    // Create image from imageData 
    UIImage *image = [UIImage imageWithData:imageData]; 
    CGImageRef cgimage = image.CGImage; 

    size_t width = CGImageGetWidth(cgimage); 
    size_t height = CGImageGetHeight(cgimage); 

    size_t bpr = CGImageGetBytesPerRow(cgimage); 
    size_t bpp = CGImageGetBitsPerPixel(cgimage); 
    size_t bpc = CGImageGetBitsPerComponent(cgimage); 
    size_t bytes_per_pixel = bpp/bpc; 

    // Get CGDataProviderRef from cgimage 
    CGDataProviderRef provider = CGImageGetDataProvider(cgimage); 

    // This is the object that is not being released 
    NSData *data = (__bridge_transfer NSData *)CGDataProviderCopyData(provider);  //Using (__bridge_transfer NSData *) casts the provider to type NSData and gives ownership to ARC, but still not discarded 

    const UInt8 *bytes = (Byte *)[data bytes]; 

    // Log which file is currently being iterated through 
    NSLog(@"---Stitching png file to total image: %@", file); 

    // Populate byte array with channel data from each pixel 
    for(size_t row = 0; row < height; row++) 
    { 
     for(size_t col = 0; col < width; col++) 
     { 
      const UInt8* pixel = 
      &bytes[row * bpr + col * bytes_per_pixel]; 

      for(unsigned short i = 0; i < 4; i+=4) 
      { 
       __unused unsigned short red = pixel[i];   // red channel - unused 
       unsigned short green = pixel[i+1];    // green channel 
       unsigned short blue = pixel[i+2];    // blue channel 
       __unused unsigned short alpha = pixel[i+3];  // alpha channel - unused 

       // Create dicom intensity value from intensity = [(g *250) + b] 
       unsigned short dicomInt = ((green * 256) + blue); 

       //Convert unsigned short intensity value to NSNumber so can store in array as object 
       NSNumber *DICOMvalue = [NSNumber numberWithInt:dicomInt]; 

       // Add to image array (total image) 
       [byteArray addObject:DICOMvalue]; 
      } 
     } 
    } 
    data = nil; 
} 
return byteArray; 

Выполнение «Анализа» через Xcode также не обнаруживает никаких явных утечек.

ответ

1

Я принял этот код почти дословно и сделал еще несколько исследований. С CFDataRef/NSData я смог увидеть проблему, с которой вы сталкивались, когда NSDatas не уходит, и я смог ее решить, обернув часть кода, использующего NSData, в области @autoreleasepool, например:

// Create array to add all files into total image 
NSMutableArray *byteArray = [[NSMutableArray alloc] initWithCapacity:(imageHeight * imageWidth)]; 

// Iterate through each file in files array 
for (NSString *file in array) 
{   
    // Set baseURL for individual file path 
    NSString *baseURL = [NSString stringWithFormat:@"http://xx.225.xxx.xxx%@",[imageInfo objectForKey:@"BaseURL"]]; 

    // Specify imagePath by appending baseURL to file name 
    NSString *imagePath = [NSString stringWithFormat:@"%@%@", baseURL, file]; 

    // Change NSString --> NSURL --> NSData 
    NSURL *imageUrl = [NSURL URLWithString:imagePath]; 
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl]; 

    // Create image from imageData 
    UIImage *image = [UIImage imageWithData:imageData]; 
    CGImageRef cgimage = image.CGImage; 

    size_t width = CGImageGetWidth(cgimage); 
    size_t height = CGImageGetHeight(cgimage); 

    size_t bpr = CGImageGetBytesPerRow(cgimage); 
    size_t bpp = CGImageGetBitsPerPixel(cgimage); 
    size_t bpc = CGImageGetBitsPerComponent(cgimage); 
    size_t bytes_per_pixel = bpp/bpc; 

    // Get CGDataProviderRef from cgimage 
    CGDataProviderRef provider = CGImageGetDataProvider(cgimage); 

    @autoreleasepool 
    { 
     // This is the object that is not being released 
     NSData *data = (__bridge_transfer NSData *)CGDataProviderCopyData(provider);  //Using (__bridge_transfer NSData *) casts the provider to type NSData and gives ownership to ARC, but still not discarded 

     const UInt8 *bytes = (Byte *)[data bytes]; 

     // Log which file is currently being iterated through 
     NSLog(@"---Stitching png file to total image: %@", file); 

     // Populate byte array with channel data from each pixel 
     for(size_t row = 0; row < height; row++) 
     { 
      for(size_t col = 0; col < width; col++) 
      { 
       const UInt8* pixel = 
       &bytes[row * bpr + col * bytes_per_pixel]; 

       for(unsigned short i = 0; i < 4; i+=4) 
       { 
        __unused unsigned short red = pixel[i];   // red channel - unused 
        unsigned short green = pixel[i+1];    // green channel 
        unsigned short blue = pixel[i+2];    // blue channel 
        __unused unsigned short alpha = pixel[i+3];  // alpha channel - unused 

        // Create dicom intensity value from intensity = [(g *250) + b] 
        unsigned short dicomInt = ((green * 256) + blue); 

        //Convert unsigned short intensity value to NSNumber so can store in array as object 
        NSNumber *DICOMvalue = [NSNumber numberWithInt:dicomInt]; 

        // Add to image array (total image) 
        [byteArray addObject:DICOMvalue]; 
       } 
      } 
     } 
     data = nil; 
    } 
} 
return byteArray; 

После добавив, что @autoreleasepool, я тогда закомментирована ту часть, где вы создаете NSNumbers и поместить их в массив, и я был в состоянии видеть в шаблоне Распределения инструментов, которые на самом деле объекты CFData были сейчас выпущенный с каждым поворотом цикла.

Причина, по которой я прокомментировал часть, в которой вы создаете NSNumbers, и помещаете их в массив, заключается в том, что с этим кодом вы добавите width * height * 4 NSNumbers в byteArray. Это означает, что даже если NSData будет выпущен правильно, ваше использование кучи будет увеличиваться на width * height * 4 * <at least 4 bytes, maybe more> независимо от того, что. Возможно, это то, что вам нужно сделать, но это, конечно, затруднило мне понять, что происходит с NSDatas, потому что их размер затмевается массивом NSNumbers.

Надеюсь, что это поможет.

+0

Я пробовал обертывать цикл for с авторекламой, но до сих пор не освобождает объект данных – user2525045

+0

@ user2525045 Отредактировано с большим расчетом – ipmcc

+0

Не уверен, что я понимаю последнюю часть вашего комментария о куче, растущем без матерного. пожалуйста, уточните? – user2525045

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

  • Нет связанных вопросов^_^