我的应用程序在执行具体操作后消耗的(大量)内存有问题。基本上,它是一组大约80 HTTP
个请求(*),我必须在数据同步操作中等待所有这些请求完成。所有都在NSOperation中,由NSOperationQueue调用。我收到请求,解析JSON,并将结果保存在Core Data中,没有什么奇怪的。伪代码如下:
NSArray *idsToFetch = ...;
NSString *serverRequestFilter = ...;
//Suppose there are 80 batches, so here is one of them:
serverRequestFilter = [NSString stringWithFormat:---];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// <Setup some headers...>
NSURLSession *session = [NSURLSession sharedSession];
dispatch_group_enter(group);
[[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// <Some error handling here>
id res = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
if ([res isKindOfClass:[NSDictionary class]]) {
NSDictionary *d = [(NSDictionary *)res objectForKey:@"d"];
NSArray *results = [d objectForKey:@"results"];
d = nil;
res = nil;
// <...>
// Save in Core Data
while (i < count) {
[moc performBlockAndWait:^{
Blablabla *bp;
bp = (Blablabla *)[NSEntityDescription insertNewObjectForEntityForName:@"Blablabla" inManagedObjectContext:moc];
NSDictionary *rel = results[i];
[bp setXXX:[rel valueForKey:@"XXX"]];
// <the same for about 10 attributes>
}
}
// <Core data save>
dispatch_group_leave(group);
}
}] resume];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
此时,内存消耗可高达120Mb。我可以继续使用该应用程序,将它放在后台,或者其他什么,我必须让内存泄漏的母亲。 如果我离开此视图控制器,内存消耗将保持较高。
我描述了应用程序,看到大量内存泄漏到字符串中(?),但我不知道如何修复它。
在个人资料中挖掘,来自该字符串的顶级“负责人”是:
- [NSPlaceholderString initWithFormat:locale:arguments:] (15k+)
- [NSSQLCore _prepareDictionaryResultsFromResultSet:usingFetchPlan:] (15k+)
- [NSURL(NSURL) initWithString:relativeToURL:] (the number of HTTP requests)
提前致谢
(*)由于服务器的限制,我必须这样做。我必须获取很多实体,所以我用分页来做。
答案 0 :(得分:1)
在使用块和内存管理时,请考虑以下几点:
尝试使用类级别实例变量的弱引用。
dispatch_group_enter(group);
[[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// <Some error handling here>
id res = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
if ([res isKindOfClass:[NSDictionary class]]) {
NSDictionary *d = [(NSDictionary *)res objectForKey:@"d"];
NSArray *results = [d objectForKey:@"results"];
d = nil;
res = nil;
// <...>
// Save in Core Data
// CHANGE: optimize memory with autorelease pool
@autoreleasepool{
__block NSInteger localCount = count;
[moc performBlockAndWait:^{
// CHANGE: add while loop inside performBlock, because, perform block in loop on managedobjectcontext is quite costly
while (i < localCount) {
Blablabla *bp;
bp = (Blablabla *)[NSEntityDescription insertNewObjectForEntityForName:@"Blablabla" inManagedObjectContext:moc];
NSDictionary *rel = results[i];
[bp setXXX:[rel valueForKey:@"XXX"]];
// <the same for about 10 attributes>
}
}
// <Core data save>
}
dispatch_group_leave(group);
}
}] resume];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);