下载大量图像时出现内存泄漏问题
Posted
技术标签:
【中文标题】下载大量图像时出现内存泄漏问题【英文标题】:Memory leak issue while downloading large number of images 【发布时间】:2012-04-06 07:30:09 【问题描述】:我正在尝试使用屏幕顶部的进度表循环下载 600 多张图像给用户。我用淡入淡出层挡住了我的屏幕以显示活动和进度。
我在应用程序崩溃之间收到内存警告消息。
我到达循环的步骤是:
-
在应用程序委托上,我检查第一个核心数据表中 isImageAvailable bool 字段中具有“0”值的所有行。
如果显示一些计数(例如 600),我会显示并使用“是”和“否”选项发出警报。
是:[self performSelector:@selector(myDownload:) withObject:nil afterDelay:0.2];
在我的下载中
NSOperationQueue *queue = [NSOperationQueue new];
// Create our NSInvocationOperation to call loadDataWithOperation, passing in nil
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(startUpdatingRecords:) object:nil];
// Add the operation to the queue
[queue addOperation:operation];
[operation release];
[queue release];
在 startUpdatingRecords 中:
-(void)startUpdatingRecords:(id)sender
[self performSelectorInBackground:@selector(updateProgressMeter:) withObject: [NSString stringWithFormat:@"%d",self.loopStartIndex]];
// Variable declarations
CGSize newSizeLarge ;
NSPredicate *predicate;
NSMutableArray *MatchingID;
Image_DB *data;
// Cache Directory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSData *responseData; // = [[NSData alloc]init] ;
NSURL *url = [[[NSURL alloc]init] autorelease];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc]init] autorelease];
UIImage *imgSelected_Large = [[[UIImage alloc]init] autorelease];
// Loop through all IDs
for (int i = 0; i < [self.arrayOfID count]; i++) //for (int i = loopStart; i < loopEnd; i++)
if (self.abortDownload)
break;
NSString *documentsDirectory = [[[NSString alloc] initWithFormat:@"%@",[paths objectAtIndex:0]] autorelease];
documentsDirectory = [paths objectAtIndex:0];
documentsDirectory = [documentsDirectory stringByAppendingFormat:@"/ImageFolder"]; // Image folder path
myClass *classObj = [self.arrayOfID objectAtIndex:i];
NSString *strURl = [[[NSString alloc] initWithFormat:@"%@%@", self.MyURL,recipeObj.recipeImageStr] autorelease];
//NSLog(@"URL = %@",strURl);
url = [NSURL URLWithString:strURl];
request = [NSMutableURLRequest requestWithURL:url];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL]; // Get Image Data into NSData
//imgSelected_Large = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:strURl]]];
NSLog(@"Download Count = %d",i+1);
if (responseData != nil)
imgSelected_Large = [UIImage imageWithData:responseData];
// Resizining image
newSizeLarge.width = 320;
newSizeLarge.height = 180;
imgSelected_Large = [self imageWithImage:imgSelected_Large scaledToSize:newSizeLarge]; // New sized image
NSData *dataPhoto; // no need to release it because UIImageJPEGRepresentation gives autoreleased NSData obj.
dataPhoto = UIImageJPEGRepresentation(imgSelected_Large, 0.6); // Set new image representation and its Compression Quality
documentsDirectory = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"Image_%d", classObj.nodeID]];
[dataPhoto writeToFile:documentsDirectory atomically:YES]; //Write file to local folder at default path
predicate = [NSPredicate predicateWithFormat: @"(image_ID = %d )",recipeObj.nodeID];
MatchingID = [CoreDataAPIMethods searchObjectsInContext:@"Image_DB" :predicate :@"image_ID" :YES :self.managedObjectContext];
// Setting flag variable for available image
for (int j = 0; j< [MatchingID count]; j++)
//Assign the Authors Records in Class Object and save to Database
data = (Image_DB*) [MatchingID objectAtIndex:j];
// data.image_large = dataPhoto; // Code for storing BLOB object to DB
data.extra_1 = @"1";
//NSLog(@"Flag updated");
// Exit out code
if ( i == [self.arrayOfID count] - 1 || i == [self.arrayOfID count]) // Its the last record to be stored
NSError *error;
if (![self.managedObjectContext save:&error])
// Handle the error...
NSLog(@"Error in updating %@",error);
self.isUpdateImageCalled = NO;
[self performSelectorOnMainThread:@selector(removeProgressMeter) withObject:nil waitUntilDone:NO];
// Update UI screen while in downloading process
[self performSelectorInBackground:@selector(updateProgressMeter:) withObject:[NSString stringWithFormat:@"%d",self.loopStartIndex+i+1]];
如果我没有释放 responseData,那么我的应用会向我显示内存警告并崩溃。如果我当时释放,[NSConcreteMutableData release]: message sent to deallocated instance 0x1e931de0 错误发生。
如何优化我的代码。任何人都可以建议我对我的代码进行修改并重新编写代码。
请帮帮我。
【问题讨论】:
希望这个链接能帮到你!! ***.com/questions/3703734/… 【参考方案1】:sendSynchronousRequest
返回的 responseData
是自动释放的,因此你不应该自己释放它。乍一看,我没有在您的代码中看到内存泄漏。您的应用程序可能实际上使用了太多内存,而没有泄漏它。尝试在你的 for 循环中放置一个自动释放池:
for (...)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// your original code with a lot of autoreleased objects
[pool release];
如果您将代码包装在自动释放池中,所有在包装内发送 autorelease
消息的对象将在释放池本身时实际释放:这样您就可以清除内存在每个 for 循环中。
另请参阅文档中的Using Autorelease Pools,它特别提到您应该在“如果您编写一个创建许多临时对象的循环”的情况下使用它们。
【讨论】:
以上是关于下载大量图像时出现内存泄漏问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 pthread_create 时出现 valgrind 内存泄漏错误
我在 Android 中使用 ListActivity 时出现内存泄漏
使用 BeautifulSoup 和 Requests 解析 html 页面源时出现内存泄漏