UIImageJPEGRepresentation收到内存警告

在使用UIImageJPEGRepresentation时收到内存警告,有什么办法可以避免这种情况? 它不会崩溃的应用程序,但我想避免它,如果可能的话。 它间歇性地不运行[[UIApplication sharedApplication] openURL:url];

 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage]; NSData *imageToUpload = UIImageJPEGRepresentation(image, 1.0); // code that sends the image to a web service (omitted) // on success from the service // this sometime does not get run, I assume it has to do with the memory warning? [[UIApplication sharedApplication] openURL:url]; } 

使用UIImageJPEGRepresentation (其中你是通过UIImage往返资产)可能会有问题,因为使用1.0的compressionQuality质量,生成的NSData实际上可以比原始文件大得多。 (另外,您在UIImage保留了图像的第二个副本。)

例如,我刚刚从iPhone的照片库中挑选了一个随机图像,原始资源为1.5mb,但UIImageJPEGRepresentation生成的compressionQuality为1.0的NSData需要6.2mb。 在UIImage保存图像本身可能会占用更多的内存(因为如果解压缩,则可能需要每个像素四个字节)。

相反,您可以使用getBytes方法获取原始资产:

 static NSInteger kBufferSize = 1024 * 10; - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { NSURL *url = info[UIImagePickerControllerReferenceURL]; [self.library assetForURL:url resultBlock:^(ALAsset *asset) { ALAssetRepresentation *representation = [asset defaultRepresentation]; long long remaining = representation.size; NSString *filename = representation.filename; long long representationOffset = 0ll; NSError *error; NSMutableData *data = [NSMutableData data]; uint8_t buffer[kBufferSize]; while (remaining > 0ll) { NSInteger bytesRetrieved = [representation getBytes:buffer fromOffset:representationOffset length:sizeof(buffer) error:&error]; if (bytesRetrieved <= 0) { NSLog(@"failed getBytes: %@", error); return; } else { remaining -= bytesRetrieved; representationOffset += bytesRetrieved; [data appendBytes:buffer length:bytesRetrieved]; } } // you can now use the `NSData` } failureBlock:^(NSError *error) { NSLog(@"assetForURL error = %@", error); }]; } 

这样可以避免在UIImage映像,所产生的NSData可以(对于照片来说)小得多。 请注意,这也有一个好处,它保留了与图像相关的元数据。

顺便说一下,虽然上面的代码显着改善了内存,但是您可能会看到更显着的内存减less机会:具体来说,不是一次将整个资源加载到NSData中,现在可以将资源( NSInputStream子类)这个getBytes例程可以根据需要获取字节,而不是一次将所有东西加载到内存中)。 这个过程中有一些烦恼(见BJ荷马关于这个主题的文章 ),但是如果你正在寻找内存占用的大幅减less,那就是这样。 这里有几个方法(BJ,使用一些分段文件和stream式传输,等等),但关键是stream媒体可以大大减less你的内存占用。

但是通过避免UIImageJPEGRepresentation UIImage (它避免了图像占用的内存以及UIImageJPEGRepresentation产生的较大的NSData ),您可能会取得相当大的进展。 此外,你可能想要确保你没有这个图像数据一次在内存中的冗余副本(例如,不要将图像数据加载到NSData ,然后为HTTPBody构build第二个NSData …看看你是否可以一下子做到这一点)。 如果最差的情况变得更糟,你可以追求stream式方法。

呈现为格式和图像的答案。

使用仪器检查由于保留但未泄漏的内存而导致的泄漏和内存丢失。 后者是尚未使用的内存,仍然指向。 在仪器上的分配仪器中使用标记生成(Heapshot)。

有关如何使用Heapshot查找内存升级,请参阅: bbum博客

基本上这个方法是运行Instruments分配工具,获取heapshot,运行你的代码迭代,并重复3或4次heapshot。 这将指示在迭代过程中分配和释放的内存。

要弄清楚结果披露,看个人的分配。

如果您需要查看对象使用工具的保留,发布和自动释放的位置:

在仪器上运行,在Allocations中设置“logging参考计数”(对于Xcode 5及更低版本,您必须停止logging以设置选项)。 导致应用程序运行,停止logging,向下钻取,您将能够看到所有保留,发布和autoreleases发生。

在ARC中:把你的代码放在@autoreleasepool的小块里面

  @autoreleasepool { NSData *data = UIImageJPEGRepresentation(img, 0.5); // something with data }