14

我正在实现一个需要通过 HTTP 获取大量图像的 iOS 应用程序。我尝试了几种方法,但独立于我所做的事情,Instuments 显示内存分配不断增加,当我在设备上运行它时,应用程序迟早会崩溃。仪器显示没有泄漏。

到目前为止,我已经尝试了以下方法:

  • 使用 NSOperation 中的同步 NSURLConnection 获取图像
  • 使用 NSOperation 中的异步 NSURLConnection 获取图像
  • 在主线程中使用 [NSData dataWithContentsOfURL:url] 获取图像
  • 使用 NSOperation 中的同步 ASIHTTPRequest 获取图像
  • 使用异步 ASIHTTPRequest 获取图像并将其添加到 NSOperationQueue
  • 使用异步 ASIHTTPRequest 并使用 completionBlock 获取图像

Instrumetns 中的调用树显示在处理 HTTP 响应时会消耗内存。在异步 NSURLConnection 的情况下,这是在

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
}  

在同步 NSURLConnection 的情况下,Instruments 会显示一个不断增长的 CFData(存储)条目。ASIHTTPRequest 的问题似乎与类似代码位置中的异步 NSURLConnection 相同。[NSData dataWithContentsOfURL:url] 方法恰好在该语句中显示了不断增加的总内存分配量。

当请求在单独的线程中完成时,我正在使用 NSAutoReleasePool 并且我尝试使用 [[NSURLCache sharedURLCache] removeAllCachedResponses] 释放内存 - 没有成功。

解决问题的任何想法/提示?谢谢。

编辑: 仅当我使用 CoreData 保存图像时才会显示该行为。这是我作为 NSInvocationOperation 运行的代码:

-(void) _fetchAndSave:(NSString*) imageId {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *url = [NSString stringWithFormat:@"%@%@", kImageUrl, imageId];
HTTPResponse *response = [SimpleHTTPClient GET:url headerOrNil:nil];
NSData *data = [response payload];

if(data && [data length] > 0) {
    UIImage *thumbnailImage = [UIImage imageWithData:data];
    NSData *thumbnailData = UIImageJPEGRepresentation([thumbnailImage scaleToSize:CGSizeMake(55, 53)], 0.5); // UIImagePNGRepresentation(thumbnail); 

    [self performSelectorOnMainThread:@selector(_save:) withObject:[NSArray arrayWithObjects:imageId, data, thumbnailData, nil] waitUntilDone:NO];
}
[pool release];
}

所有与 CoreData 相关的东西都在这里的主线程中完成,所以不应该有任何 CoreData 多线程问题。但是,如果我保留图像,仪器会在上述位置显示不断增加的内存分配。

编辑二:

CoreData相关代码:

-(void) _save:(NSArray*)args {
NSString *imageId = [args objectAtIndex:0];
NSData *data = [args objectAtIndex:1];
NSData *thumbnailData = [args objectAtIndex:2];

Image *image = (Image*)[[CoreDataHelper sharedSingleton] createObject:@Image];
image.timestamp =  [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]];
image.data = data;

Thumbnail *thumbnail = (Thumbnail*)[[CoreDataHelper sharedSingleton] createObject:@"Thumbnail"];
thumbnail.data = thumbnailData;
thumbnail.timestamp = image.timestamp;
[[CoreDataHelper sharedSingleton] save];
}

从 CoreDataHelper (self.managedObjectContext 正在选择当前线程中可用的 NSManagedObjectContext):

-(NSManagedObject *) createObject:(NSString *) entityName {
return [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self.managedObjectContext];
}
4

2 回答 2

9

我们遇到了类似的问题。通过 http 获取大量图像时,内存分配出现了巨大的增长和锯齿模式。我们会看到系统或多或少地在进行清理,但速度很慢,而且无法预测。与此同时,下载量不断涌入,堆积在记忆中的任何东西上。内存分配将达到 200M 左右,然后我们就死了。

问题是 NSURLCache 问题。您说您尝试了 [[NSURLCache sharedURLCache] removeAllCachedResponses]。我们也尝试过,但后来尝试了一些不同的东西。

我们的下载是在N个图像/电影的组中完成的,其中N通常为 50 到 500。重要的是我们将所有N作为原子操作。

在我们开始我们的 http 下载组之前,我们这样做了:

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:0];
[NSURLCache setSharedURLCache:sharedCache];

然后,我们通过同步调用通过 http获取N中的每个图像。我们在 NSOperation 中进行此组下载,因此我们不会阻止 UI。

NSData *movieReferenceData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 

最后,在每个单独的图像下载之后,并且在我们完成了该图像的 NSData 对象之后,我们调用:

[sharedCache removeAllCachedResponses]; 

我们的内存分配峰值行为下降到非常舒适的几兆字节,并且停止增长。

于 2012-02-29T22:12:47.520 回答
0

在这种情况下,您看到的正是您应该看到的。-[NSMutableData appendData:]增加其内部缓冲区的大小以保存新数据。由于 anNSMutableData始终位于内存中,这会导致内存使用量相应增加。你期待什么?

如果这些图像的最终目的地在磁盘上,请尝试使用NSOutputStream. NSMutableData如果你想显示图像,你可以UIImage在完成后创建一个指向文件的指针。

于 2011-02-07T14:38:49.313 回答