【发布时间】:2014-11-01 12:41:55
【问题描述】:
我的代码中存在内存泄漏问题,我需要快速连续获取多个 URL,每个 GET 都会受到前一个 GET 的结果的影响。目的是在响应中查找特定的内容。
我发现最简洁的实现方式是递归,因为我可以使用相同的方法来确定响应中是否存在所需的值。从功能上讲,它工作得很好,但它会泄漏内存,如下所述。我还以迭代方式实现了相同的功能,这也会泄漏内存。
在我看来,NSURLSession API 似乎负责泄漏此内存,并且仅在非常快速地连续进行多次调用时才会发生。但是,如果有人能指出我所犯的任何明显错误,我将不胜感激。
10/09/14 更新:
更新为添加递归计数器,表明即使代码未无限次执行,泄漏仍然会发生。还稍微整理了实现,在视图控制器中重新使用 NSURLSession 和 NSURLSessionConfiguration 作为属性。
示例代码:
- (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;
}
仪器报告的内存泄漏。 (注意:这些每次都略有不同,但大部分都包含相同的泄漏,只是或多或少相同的泄漏):
进一步更新:
所以,我实际上迭代地实现了相同的代码,内存泄漏仍然发生。对于这个例子,我包含了一个循环限制器,所以它不会永远执行。谁能帮我弄清楚这里到底发生了什么?
- (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);
}
10/09/14 更新:
iOS 8 上的任何 Google 员工仍然会在 iOS 8 上找到自己的出路。就我而言,这是 iOS 中的一个错误。
【问题讨论】:
-
你使用ARC还是MRC?
-
iOS8上真的解决了吗?我有完全相同的问题。它现在对你有用吗?
-
不,抱歉。它似乎已在 iOS 8 GM 版本中得到修复,但现在在 iOS 8 的已发布版本中再次出现。
-
好像我也遇到了同样的问题,你找到解决办法了吗?
标签: ios objective-c recursion memory-leaks nsurlsession