2013-08-28 49 views
0

好吧,所以我從服務器中分段下載了一堆大圖像(5mb),然後將這些碎片拼接在一起並渲染來自字節數組的整個圖像。但是,我意識到每個圖像的數據都沒有被釋放,並因此導致內存警告和應用程序崩潰。我認爲,因爲我明確(__bridge_transfer NSData *)鑄造ARC會照顧釋放對象,但它仍然證明是一個問題。在樂器中,約1mb的對象稱爲「CGDataProviderCopyData」,對於每個正在拼接到整個圖像中的文件都不會丟棄。任何想法或任何能引導我走向正確方向的人?多謝。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不會消失的問題,並且我可以通過在@autoreleasepool範圍內包裝使用NSData的代碼部分來解決此問題,如下所示:

// 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

我試圖用autorelease包裝for循環,但仍然不釋放數據對象 – user2525045

+0

@ user2525045編輯與更多的調查 – ipmcc

+0

不知道我瞭解你的評論的最後一部分關於堆增長沒有什麼。你能澄清一下嗎? – user2525045