从使用Instruments
进行分析后,我了解到将图像保存到磁盘的方式会导致内存峰值~60MB
。这会导致应用程序发出low memory warnings
,这会导致iPhone4S
正在运行iOS7
的崩溃(不一致)。
我需要最有效的方法将图像保存到磁盘。
我目前正在使用此代码
+ (void)saveImage:(UIImage *)image withName:(NSString *)name {
NSData *data = UIImageJPEGRepresentation(image, 1.0);
DLog(@"*** SIZE *** : Saving file of size %lu", (unsigned long)[data length]);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
[fileManager createFileAtPath:fullPath contents:data attributes:nil];
}
说明:
减少compressionQuality
中UIImageJPEGRepresentation
参数的值并不会显着降低内存峰值。
例如
在compressionQuality = 0.8
次写入时,3MB
的内存峰值平均减少了100
。
但是,它确实减少了磁盘上的数据大小(显然),但这对我没有帮助。
UIImagePNGRepresentation
取代UIImageJPEGRepresentation
对此更糟糕。速度较慢,导致峰值较高。
this approach与ImageIO
的效率是否更高?如果是这样的话?
如果有人有任何建议,那就太棒了。感谢
修改
注意以下问题中列出的一些要点。
a)虽然我正在保存多个图像,但我没有将它们保存在循环中。我做了一些阅读和测试,发现自动释放池不会帮助我。
b)照片的大小各不为60Mb。他们是在iPhone 4S上拍摄的照片。
考虑到这一点,我回去试图克服我认为的问题;第NSData *data = UIImageJPEGRepresentation(image, 1.0);
行。
导致崩溃的内存峰值可以在下面的屏幕截图中看到。他们对应于UIImageJPEGRepresentation
被召唤的时间。我还跑Time Profiler
和System Usage
,这使我指向了同一个方向。
长话短说,我转到AVFoundation
并使用
photoData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
返回类型为NSData
的对象,然后我将其用作使用NSFileManager写入的数据。
这样可以完全消除内存中的尖峰。
即
[self saveImageWithData:photoData];
,其中
+ (void)saveImageWithData:(NSData *)imageData withName:(NSString *)name {
NSData *data = imageData;
DLog(@"*** SIZE *** : Saving file of size %lu", (unsigned long)[data length]);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
[fileManager createFileAtPath:fullPath contents:data attributes:nil];
}
PS:我还没有把这个问题作为一个问题的答案,因为人们觉得它没有回答“在iPhone上将照片保存到磁盘上的大多数内存有效的方法吗?”。但是,如果达成共识,我应该更新它。
感谢。
答案 0 :(得分:4)
使用UIImageJPEGRepresentation要求您同时在内存中保留原始和最终图像。它也可能会暂时缓存完全渲染的图像,这会占用大量内存。
您可以尝试使用CGImageDestination。我不知道它的内存效率如何,但它有可能将图像直接流式传输到磁盘上。
+(void) writeImage:(UIImage *)inImage toURL:(NSURL *)inURL withQuality:(double)inQuality {
CGImageDestinationRef destination = CGImageDestinationCreateWithURL( (CFURLRef)inURL , kUTTypeJPEG , 1 , NULL );
CFDictionaryRef properties = (CFDictionaryRef)[NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:inQuality] forKey:kCGImageDestinationLossyCompressionQuality];
CGImageDestinationAddImage( destination , [inImage CGImage] , properties );
CGImageDestinationFinalize( destination );
CFRelease( destination );
}
答案 1 :(得分:2)
你的图片实际上是60MB压缩的吗?如果它们是,如果您想将它们保存为单个JPEG文件,则无法做很多事情。您可以尝试将它们渲染为较小的图像,或者将它们平铺并将它们保存到单独的文件中。
我不希望您的ImageIO代码段改进任何内容。如果有两行修复,那么UIImageJPEGRepresentation
将在内部使用它。
但是我打赌你没有从单张图片中获得60MB。我打赌你从循环中保存的多个图像中获得60MB。如果是这样的话,那么你可以做些什么。在您的循环中放置@autoreleasepool{}
。很可能你正在积累自动释放的物体,这导致了尖峰。在循环中添加一个池可以让它耗尽。
答案 2 :(得分:-1)
尝试使用NSAutoReleasePool并在完成数据写入后将池耗尽。