ios - CGDataProviderCopyData builds up in memory causing crash -
okay, i'm downloading bunch of large-ish images (5mb) server in pieces, stitching pieces , rendering total image byte array. however, i've realized data each image not being released, , consequently builds causing memory warning , crash of app. thought because of explicit (__bridge_transfer nsdata *) casting arc take care of releasing object, it's still proving problem. in instruments, objects called "cgdataprovidercopydata" of ~ 1mb build , not discarded each file being stitched whole image. ideas or can steer me in right direction? obliged.
// create array add files total image nsmutablearray *bytearray = [[nsmutablearray alloc] initwithcapacity:(imageheight * imagewidth)]; // iterate through each file in files array (nsstring *file in array) { // set baseurl individual file path nsstring *baseurl = [nsstring stringwithformat:@"http://xx.225.xxx.xxx%@",[imageinfo objectforkey:@"baseurl"]]; // specify imagepath appending baseurl file name nsstring *imagepath = [nsstring stringwithformat:@"%@%@", baseurl, file]; // change nsstring --> nsurl --> nsdata nsurl *imageurl = [nsurl urlwithstring:imagepath]; nsdata *imagedata = [nsdata datawithcontentsofurl:imageurl]; // create image 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; // cgdataproviderref cgimage cgdataproviderref provider = cgimagegetdataprovider(cgimage); // object not being released nsdata *data = (__bridge_transfer nsdata *)cgdataprovidercopydata(provider); //using (__bridge_transfer nsdata *) casts provider type nsdata , gives ownership arc, still not discarded const uint8 *bytes = (byte *)[data bytes]; // log file being iterated through nslog(@"---stitching png file total image: %@", file); // populate byte array channel data 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 = 0; < 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 intensity = [(g *250) + b] unsigned short dicomint = ((green * 256) + blue); //convert unsigned short intensity value nsnumber can store in array object nsnumber *dicomvalue = [nsnumber numberwithint:dicomint]; // add image array (total image) [bytearray addobject:dicomvalue]; } } } data = nil; } return bytearray;
running "analyze" through xcode doesn't show apparent leaks either.
i took code, verbatim, , did more investigation. cfdataref/nsdata, able see problem seeing nsdatas not going away, , able solve wrapping portion of code uses nsdata in @autoreleasepool
scope, this:
// create array add files total image nsmutablearray *bytearray = [[nsmutablearray alloc] initwithcapacity:(imageheight * imagewidth)]; // iterate through each file in files array (nsstring *file in array) { // set baseurl individual file path nsstring *baseurl = [nsstring stringwithformat:@"http://xx.225.xxx.xxx%@",[imageinfo objectforkey:@"baseurl"]]; // specify imagepath appending baseurl file name nsstring *imagepath = [nsstring stringwithformat:@"%@%@", baseurl, file]; // change nsstring --> nsurl --> nsdata nsurl *imageurl = [nsurl urlwithstring:imagepath]; nsdata *imagedata = [nsdata datawithcontentsofurl:imageurl]; // create image 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; // cgdataproviderref cgimage cgdataproviderref provider = cgimagegetdataprovider(cgimage); @autoreleasepool { // object not being released nsdata *data = (__bridge_transfer nsdata *)cgdataprovidercopydata(provider); //using (__bridge_transfer nsdata *) casts provider type nsdata , gives ownership arc, still not discarded const uint8 *bytes = (byte *)[data bytes]; // log file being iterated through nslog(@"---stitching png file total image: %@", file); // populate byte array channel data 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 = 0; < 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 intensity = [(g *250) + b] unsigned short dicomint = ((green * 256) + blue); //convert unsigned short intensity value nsnumber can store in array object nsnumber *dicomvalue = [nsnumber numberwithint:dicomint]; // add image array (total image) [bytearray addobject:dicomvalue]; } } } data = nil; } } return bytearray;
after adding @autoreleasepool
, commented out part create nsnumbers , put them in array, , able see in allocations template of instruments indeed cfdata objects being released each turn of loop.
the reason commented out part create nsnumbers , put them in array, code in there, you're going end adding width * height * 4
nsnumbers bytearray
. means if nsdata being released properly, heap use going width * height * 4 * <at least 4 bytes, maybe more>
no matter what. maybe that's need do, sure made harder me see going on nsdatas because size being dwarfed array of nsnumbers.
hope helps.
Comments
Post a Comment