递归/迭代NSURLSessionDataTask导致内存泄漏

Sam*_*io2 8 recursion memory-leaks objective-c ios nsurlsession

我的代码中存在内存泄漏问题,我需要快速连续获取许多URL,每个GET都受到前一个GET结果的影响.目的是在响应中查找特定内容.

我发现最简洁的方法是递归地实现它,因为我可以使用相同的方法来确定响应中是否存在所需的值.功能上它非常好用,但它会泄漏内存,如下所述.我也以迭代的方式实现了相同的功能,这也泄漏了内存.

在我看来,似乎NSURLSessionAPI负责泄漏这个内存,它只发生在很快连续多次调用时.但是,如果有人能指出我正在犯的任何明显错误,我将不胜感激.

2014年9月14日更新:

更新以添加递归计数器,即使代码未执行无限次,也可以证明泄漏仍然存在.还略微整理了实现,在视图控制器中重新使用NSURLSessionNSURLSessionConfiguration作为属性.

示例代码:

- (void)performURLCallRecursive {

    recursionLimiter++;

    if (recursionLimiter > 10) {
        [self.session finishTasksAndInvalidate];
        return;
    }

    NSURL * checkURL = [NSURL URLWithString:@"http://www.google.com"];

    __block NSMutableURLRequest * urlRequest = [[NSMutableURLRequest alloc] initWithURL:checkURL
                                                                            cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                                        timeoutInterval:0.0f];

    __weak typeof(self) weakSelf = self;

    NSURLSessionDataTask * task = [self.session dataTaskWithRequest:urlRequest
                                                  completionHandler:^(NSData *data, NSURLResponse *response, NSError
*error) {

                                                      NSString * body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                                      NSLog(@"Body: %@", body);

                                                      [weakSelf performURLCallRecursive];

                                                  }];

    [task resume];
 }

#pragma mark - Getters

- (NSURLSessionConfiguration *)sessionConfiguration {

    if (!_sessionConfiguration) {

        _sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];

        [_sessionConfiguration setAllowsCellularAccess:NO];
        [_sessionConfiguration setTimeoutIntervalForRequest:10.0f];
        [_sessionConfiguration setTimeoutIntervalForResource:10.0f];

        [_sessionConfiguration setURLCache:[[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]];

    }

    return _sessionConfiguration;
 }

- (NSURLSession *)session {

    if (_session == nil) {

        _session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration
                                                 delegate:[SPRSessionDelegate new]
                                            delegateQueue:nil];

    }

    return _session; 
}
Run Code Online (Sandbox Code Playgroud)

仪器报告的内存泄漏.(注意:这些每次都略有不同,但大多数情况下包含相同的泄漏,只是或多或少相同的泄漏):

显示报告内存泄漏的仪器的图像

进一步更新:

所以,我实际上迭代地实现了相同的代码,并且仍然发生内存泄漏.对于这个例子,我包含了一个循环限制器,因此它永远不会执行.任何人都可以帮我弄清楚这里到底发生了什么?

- (void)performURLCallIterative
{

    int loopLimiter = 0;

    do {

        NSURLSessionConfiguration * defaultSession = [NSURLSessionConfiguration defaultSessionConfiguration];

        [defaultSession setAllowsCellularAccess:NO];
        [defaultSession setTimeoutIntervalForRequest:10.0f];
        [defaultSession setTimeoutIntervalForResource:10.0f];

        NSURLSession * session = [NSURLSession sessionWithConfiguration:defaultSession
                                                               delegate:self
                                                          delegateQueue:nil];


        NSURL * checkURL = [NSURL URLWithString:@"http://google.com"];

        NSMutableURLRequest * urlRequest = [[NSMutableURLRequest alloc] initWithURL:checkURL
                                                                        cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                                    timeoutInterval:0.0f];

        __weak NSURLSession * weakSession = session;

        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        NSURLSessionDataTask * task = [session dataTaskWithRequest:urlRequest
                                                 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                                                     NSString * body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                                     NSLog(@"Body: %@", body);

                                                     dispatch_semaphore_signal(semaphore);

                                                     [weakSession invalidateAndCancel];

                                                 }];

        [task resume];

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        loopLimiter++;

    } while (loopLimiter <= 6);

}
Run Code Online (Sandbox Code Playgroud)

2014年9月14日更新:

对于可能在这里找到自己的方式的任何Google员工,iOS 8上仍然会出现这种情况.就我而言,这是iOS中的一个错误.

nav*_*ast -1

我唯一的建议可能是使用 an@autoreleasepool{}并将其转换__weak id self__block id self. 我不认为__blockvs.__weak会做任何不同的事情,但尝试一下。

我不确定当异步和递归运行某些东西时,人们应该对 ARC 抱有怎样的期望。查看异步递归调用和 ARC 的其他问题,没有任何一致的解决方案。例如,看看这里。