【问题标题】:Memory pressure due to download and saving of images由于下载和保存图像导致的内存压力
【发布时间】:2014-03-25 13:28:51
【问题描述】:

幸运的是,我知道我的内存压力问题来自哪里,并且我尝试了许多技术,例如将块包装在 @autorelease 块中并将对象设置为 nil,但仍然没有成功。

很抱歉在这里倾倒了太多代码,我试图将其缩减为基本要素。这是下载和保存图片的代码:

NSMuttableArray *photosDownOps = [NSMuttableArray array];
NSURL *URL = [...];
NSURLRequest *request = [...];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFImageResponseSerializer serializer];

[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {    
    dispatch_queue_t amBgSyncQueue = dispatch_queue_create("writetoFileThread", NULL);
    dispatch_async(amBgSyncQueue, ^{
        [self savePhotoToFile:(UIImage *)responseObject usingFileName:photo.id];
    });    
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    if ([error code] !=  NSURLErrorCancelled)
        NSLog(@"Error occured downloading photos: %@", error);
}];
[photosDownOps addObject:op];

NSArray *photosDownloadOperations = [AFURLConnectionOperation batchOfRequestOperations:photosDownloadOperatons 
                                                                         progressBlock:^(NSUInteger nof, NSUInteger tno) {        
} completionBlock:^(NSArray *operations) {
    NSLog(@"all photo downloads completed");
}];

[self.photosDownloadQueue addOperations:photosDownloadOperations waitUntilFinished:NO];

+ (void) savePhotoToFile:(UIImage *)imageToSave usingFileName:(NSNumber *)photoID{
    @autoreleasepool {
        NSData * binaryImageData = UIImageJPEGRepresentation(imageToSave, 0.6);
        NSString *filePath = [Utilities fullPathForPhoto:photoID];
        [binaryImageData writeToFile:filePath atomically:YES];
        binaryImageData = nil;
        imageToSave = nil;
    }
}

这种情况虽然只发生在我测试过的 iPhone 4s 设备上,但不会发生在 iPhone 5 机型上。

【问题讨论】:

  • 您是否使用 Instruments 测量过代码的内存使用情况?这将告诉您分配来自何处,按对象类型分组以及每个实例的分配历史。您首先需要确定造成所有内存压力的对象是哪些对象,然后追踪这些对象的来源并了解它们的所有用途以了解如何继续。
  • 您要获取的图像的分辨率是多少,显示所需的最大分辨率是多少?您是否有机会缩小图像以减少整体数据?在平均应用会话中,您通常处理多少张图片?
  • 我可以看到整个图像首先下载到缓存中,然后在成功块中返回给您。如果图像大小相当大,这可能是内存峰值的原因。您应该编写自己的操作,在里面发出请求,在 NSUrlConnectionDelegate 的 didReceiveData 方法中,您接收块中的响应数据,使用 NSOutputStream 将该数据写入所需的文件位置。我想这会解决你的问题。
  • @bneely 的罪魁祸首是 VM:CG rasta 数据和 VM:ImageIO_Data,每个的总字节数为 130MB,整个应用程序的总字节数为 1.2GB。我以 480x640 的分辨率和每张
  • 你能在把它们当作 UIImage 之前将它们写入磁盘吗?获取图像后是否立即显示/使用?您可以将它们作为不透明的 NSData 处理并以这种方式将它们写入磁盘。然后你会避免不必要的 UIImage 缓存。当您需要给定图像时,从磁盘加载它,然后调用 UIImageJPEGRepresentation()。换句话说,将 UIImage 工作推迟到最后一刻。

标签: ios iphone memory-leaks out-of-memory memory-pressure


【解决方案1】:

我设法通过扩展 NSOperation 来解决这个问题,并在收到数据后立即在主块内将其写入文件:

- (void)main{
    @autoreleasepool {
        //...
        NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageUrl];        
        if (imageData) {
            NSError *error = nil;
            [imageData writeToFile:imageSavePath options:NSDataWritingAtomic error:&error];
        }
        //...
    }
}

这个 NSOperation 对象被添加了一个我已经拥有的 NSOperationQueue。

【讨论】:

    【解决方案2】:

    尝试创建您自己的类以使用 NSUrlConnection 下载图像,并在委托方法中将该数据附加到您的文件中,只需查看以下代码

    -(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data {
    
    NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:aPath]; 
    [fileHandle seekToEndOfFile]; 
    [fileHandle writeData:data]; 
    [fileHandle closeFile];
    
    }
    

    这将帮助您管理内存,因为下载的所有数据都不需要缓存。

    【讨论】:

    • 我明白了这个想法,但它对我不起作用,也许我没有正确实现它。
    猜你喜欢
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 2012-09-07
    • 2014-04-08
    • 1970-01-01
    • 2015-04-12
    相关资源
    最近更新 更多