我正在尝试将图像从UIImagePicker复制到documents目录。我使用@"UIImagePickerControllerOriginalImage"键从UIImagePickerDelegate字典中获取原始图像。我正在使用UIImagePNGRepresentation将图像写入文件。当我添加(重复处理)高分辨率图像(图像大小约为20 mb)时,我将面临内存问题。
我分析并使用了Xcode的内存泄漏特性,它放大了下面的代码,这是造成泄漏的原因。
@autoreleasepool {
imagesData = UIImagePNGRepresentation(images);
[imagesData writeToFile:name atomically:NO];
imagesData = nil;
//[UIImageJPEGRepresentation(images, 1.0) writeToFile:name atomically:YES];
}我在这里看到了许多关于UIImagePNGRepresentation造成的内存泄漏的问题。但我还没有找到解决问题的适当办法。需要帮助。
发布于 2014-08-15 06:58:47
我不知道UIImagePNGRepresentation有什么“泄漏”,但这肯定是对内存的过度使用,但这里有几个问题:
UIImage往返原始资产,然后使用UIImagePNGRepresentation()的过程效率很低,最终可能会产生一个比原始资产大得多的NSData。例如,我选择了一张照片,它的原始资产为1.5mb,UIImageJPEGRepresentation( compressionQuality为1.0)为6mb,UIImagePNGRepresentation()约为10 6mb。(这些数字在图像之间可能会发生很大的变化,但你有了基本的想法。)
您通常可以通过使用小于1.0的UIImageJPEGRepresentation (例如,0.8或0.9提供最小的图像质量损失,但在NSData站点上却明显减少)来缓解这个问题。但这是有损压缩。此外,在此过程中,您将丢失一些图像元数据。UIImage表示和NSData对象。NSData表示比它所需要的要大,您还同时将整个资产加载到内存中。这是不必要的。相反,您可以考虑将原始资产直接从ALAssetLibrary流到持久内存,而不使用UIImagePNGRepresentation或UIImageJPEGRepresentation,也根本不将其加载到UIImage中。相反,创建一个小缓冲区,通过getBytes重复地用原始资产的一部分填充这个缓冲区,在执行过程中使用NSOutputStream将这个小缓冲区写入一个临时文件。您可以重复该过程,直到将整个资产写入持久存储。该进程的总内存占用量比其他方法要低得多。
例如:
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;
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *path = [documentsPath stringByAppendingPathComponent:filename];
NSString *tempPath = [self pathForTemporaryFileWithPrefix:@"ALAssetDownload"];
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:tempPath append:NO];
NSAssert(outputStream, @"Unable to create output stream");
[outputStream open];
long long representationOffset = 0ll;
NSError *error;
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);
[outputStream close];
[[NSFileManager defaultManager] removeItemAtPath:tempPath error:nil];
return;
} else {
remaining -= bytesRetrieved;
representationOffset += bytesRetrieved;
[outputStream write:buffer maxLength:bytesRetrieved];
}
}
[outputStream close];
if (![[NSFileManager defaultManager] moveItemAtPath:tempPath toPath:path error:&error]) {
NSLog(@"Unable to move file: %@", error);
}
} failureBlock:^(NSError *error) {
NSLog(@"assetForURL error = %@", error);
}];
}
- (NSString *)pathForTemporaryFileWithPrefix:(NSString *)prefix
{
NSString *uuidString = [[NSUUID UUID] UUIDString];
// If supporting iOS versions prior to 6.0, you can use:
//
// CFUUIDRef uuid = CFUUIDCreate(NULL);
// assert(uuid != NULL);
// NSString *uuidString = CFBridgingRelease(CFUUIDCreateString(NULL, uuid));
// CFRelease(uuid);
return [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@", prefix, uuidString]];
}发布于 2016-12-22 02:21:57
我通过发送4通道映像(RGBA或RGBX)来解决这个问题,而不是3通道映像(RGB)。您可以检查是否有任何机会改变您的图像参数。
使用kCGImageAlphaNoneSkipLast而不是kCGImageAlphaNone。
https://stackoverflow.com/questions/25322138
复制相似问题