NSURLSession内存泄漏

即使使NSURLSession失效,使用Instruments运行configuration文件,一些名为TubeManager的类(可能是私有的),HTTPConnectionCache和HTTPConnectionCacheDictionary在内存中仍然存在。

代码片段重现:

NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession* session = [NSURLSession sessionWithConfiguration:config]; NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]]; NSURLSessionDataTask* sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { [session finishTasksAndInvalidate]; }]; [sessionDataTask resume]; 

仪器截图

那么,问题是什么? 你想closurescaching吗? networking响应通常caching在NSURLCache内存和永久存储中。

如果此caching使用情况有问题,请相应地更改会话configuration的requestCachePolicy 。 或者更改NSMutableURLRequest本身的cachePolicy 。 您还可以configuration会话configuration使用的URLCache的最大大小,以限制RAM使用量以及持久性内存使用量。

即使你closurescaching,一般来说,API调用不会让你感到惊讶,因为API调用会增加内存消耗。 第一次执行某项任务时,应用程序体验到一些适度的内存消耗并不罕见。 但是在应用程序运行时,在后续迭代中不应该看到相同的增长。 在跟踪内存使用情况时,通常build议多次重复任务,看看应用程序是否返回到稳定状态(这是可取的),还是继续增长(这需要进一步调查以确保代码不是问题的来源)。 但是我们很less担心最初的内存消耗,除非它是显着的。

看看你的代码片段,没有什么明显的错误。 我倾向于怀疑iOS的例行内存消耗。 假设问题比一般caching行为更广泛,如果每次应用程序执行此代码时内存消耗剧烈和/或持续增长,则提供更多详细信息,我们可以帮助您进一步诊断。


这是我的内存configuration文件看起来像四批100个请求之后, 加上一个最后的标志后,我发出了记忆警告:

在这里输入图像说明

(注意,这是一个合成图像,所以我可以在第一批之前,第三批之前,最后一批之后以及手动发布内存警告之前向您显示内存。我将它们组合在一起,以便更容易地看到总分配在那四个时间点。)

请注意,在iOS 9上,安全框架分配appx。 4k的SSLcaching数据,并在首次为新的NSURLSession对象恢复任务时向您的应用程序收费。 苹果技术问答QA1727告诉我们这个SSLcaching持续10分钟,不pipe是什么,因为它是私人的,完全由系统pipe理(因为安全!)。

在您的代码示例中,每次发出请求时都会创build一个新的NSURLSession对象。 但是你只是使用defaultSessionConfiguration而不是指定一个可能存在强引用的委托,那么你应该做的只是使用单例[NSURLSession sharedSession]并使用resetWithCompletionHandler来清除非安全分配。 或者如果你想自定义configuration,则创build一个自定义单例。

  • (NSURLSession *)sharedSession讨论

对于基本请求,URL会话类提供了一个共享的单例会话对象,为您提供合理的默认行为。 通过使用共享会话,只需几行代码就可以将URL的内容提取到内存中。

与其他会话types不同,您不会创build共享会话; 你只需要调用[NSURLSession sharedSession]来请求它。 因此,您不提供委托或configuration对象。 因此,与共享会话:

  - You cannot obtain data incrementally as it arrives from the server. - You cannot significantly customize the default connection behavior. - Your ability to perform authentication is limited. - You cannot perform background downloads or uploads while your app is not running. 

共享会话使用共享的NSURLCache,NSHTTPCookieStorage和NSURLCredentialStorage对象,使用共享的自定义networking协议列表(使用registerClass:和unregisterClass :)configuration,并且基于默认configuration。

在使用共享会话时,通常应避免自定义caching,cookie存储或凭证存储(除非您已经使用NSURLConnection),因为您很可能会超出默认会话的function在这一点上,您将不得不以适合您的自定义URL会话的方式重写所有这些自定义设置。

换句话说,如果您对caching,Cookie,身份validation或自定义networking协议做任何事情,则应该使用默认会话而不是默认会话。

(来自NSURLSession类参考…斜体我的; P)

如果你没有使用sharedSession苹果提供的单身人士,那么你至less应该从苹果公司获得一个提示,并用会话属性来sharedSession自己的单身人士。 会议的要点是,它的目的是活得比一个请求更长。 尽pipe他们的文档不清楚,但苹果提供了一个单例,并将其称为“会话”的事实表明,会话对象的寿命要长于单个请求。

是的,你应该在某个时候invalidateAndCancel ,而不是在每一个请求之后,即使每个请求都完全去了一个不同的服务器(这几乎从来就不是这样)。 如果您打算引用特定会话,则只需要使其无效并取消; 否则,可以在会话上调用flushWithCompletionHandlerresetWithCompletionHandler刷新会话的堆分配给VM,或重置以清除堆和VM存储。 (另请参阅我的答案)

finishTasksAndInvalidate在错误的地方调用… completionHandler用于处理响应它与session没有任何关系

这是正确的代码:

 NSURLSessionConfiguration* config = [NSURLSessionConfigurationdefaultSessionConfiguration]; NSURLSession* session = [NSURLSession sessionWithConfiguration:config]; NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]]; NSURLSessionDataTask* sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // handle response... }]; [sessionDataTask resume]; [session finishTasksAndInvalidate];