dispatch_group中的内存泄漏

时间:2015-11-04 09:38:09

标签: ios objective-c memory memory-leaks grand-central-dispatch

我的应用程序在执行具体操作后消耗的(大量)内存有问题。基本上,它是一组大约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。我可以继续使用该应用程序,将它放在后台,或者其他什么,我必须让内存泄漏的母亲。 如果我离开此视图控制器,内存消耗将保持较高。

我描述了应用程序,看到大量内存泄漏到字符串中(?),但我不知道如何修复它。

App memory profiling

在个人资料中挖掘,来自该字符串的顶级“负责人”是:

  - [NSPlaceholderString initWithFormat:locale:arguments:] (15k+)

  - [NSSQLCore _prepareDictionaryResultsFromResultSet:usingFetchPlan:] (15k+)

  - [NSURL(NSURL) initWithString:relativeToURL:] (the number of HTTP requests)

提前致谢

(*)由于服务器的限制,我必须这样做。我必须获取很多实体,所以我用分页来做。

1 个答案:

答案 0 :(得分:1)

在使用块和内存管理时,请考虑以下几点:

  1. 使用自动释放池优化内存以进行重循环
  2. 尝试最小化CoreData执行块,就好像我们在Core Data的后面使用SQLite持久存储一样,每个执行块都可以作为一个事务处理并且非常昂贵。
  3. 尝试使用类级别实例变量的弱引用。

    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);