首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSURLSession内存泄漏

NSURLSession内存泄漏
EN

Stack Overflow用户
提问于 2015-05-08 00:37:23
回答 3查看 4.3K关注 0票数 2

即使在使NSURLSession无效后,使用工具运行配置文件,一些名为TubeManager、HTTPConnectionCache和HTTPConnectionCacheDictionary的类(可能是私有类)仍然在内存中存活。

要重现的代码片段:

代码语言:javascript
复制
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];

EN

回答 3

Stack Overflow用户

发布于 2015-05-08 01:58:04

那么,问题是什么呢?是否要关闭缓存?网络响应通常缓存在内存和持久存储中的NSURLCache中。

如果此缓存使用有问题,请相应地更改会话配置的requestCachePolicy。或者更改NSMutableURLRequest本身的cachePolicy。您还可以配置会话配置使用的URLCache的最大大小,以限制内存使用量和持久内存使用量。

即使您关闭了缓存,作为一般规则,人们也不应对API调用增加内存消耗感到惊讶,这并非您自己的错误。对于一个应用程序来说,在第一次执行某些任务时遇到一些适度的内存消耗并不少见。但在应用程序运行时,在后续迭代中不应看到相同的增长。在跟踪内存使用情况时,通常建议多次重复该任务,并查看应用程序是否返回到某种稳定状态(这是可取的),或者它是否继续增长(这需要进一步调查以确保您的代码不是问题的根源)。但我们很少担心初始内存消耗,除非它是戏剧性的。

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

这是我的内存配置文件在四批100个请求之后的样子;加上我发出内存警告后的最后一个标志:

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

票数 0
EN

Stack Overflow用户

发布于 2016-03-06 04:05:54

请注意,在iOS 9上,安全框架分配appx。4k的SSL缓存数据,并在您第一次为新的NSURLSession对象恢复任务时将其计入您的应用程序。Apple Technical Q&A QA1727告诉我们,这个SSL缓存会持续10分钟,因为它是私有的,完全由系统管理(因为安全性!)。

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

  • (NSURLSession *)sharedSession Discussion

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

与其他会话类型不同,您不需要创建共享会话;您只需通过调用NSURLSession sharedSession来请求它。因此,您不需要提供委托或配置对象。因此,使用共享会话:

代码语言:javascript
复制
- 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对象,使用共享的自定义网络协议列表(使用registerClass:和unregisterClass:配置),并且基于默认配置。

在使用共享会话时,通常应避免自定义缓存、cookie存储或凭据存储(除非您已经在使用NSURLConnection执行此操作),因为很有可能最终会超出默认会话的能力,此时您必须以一种与自定义URL会话一起工作的方式重写所有这些自定义。

换句话说,如果您正在使用缓存、cookie、身份验证或自定义网络协议执行任何操作,那么您可能应该使用默认会话,而不是默认会话。

(来自NSURLSession类参考...斜体矿山;P)

如果你没有使用苹果提供的sharedSession单例,那么你至少应该从苹果那里得到一个提示,并使用会话属性来滚动你自己的单例。会话的意义在于,它的生存时间不只是一个请求。尽管他们的文档不清楚,但事实上苹果提供了一个单例,并将其称为“会话”,这表明会话对象的生存时间应该比单个请求更长。

是的,你应该在某个时刻invalidateAndCancel,但不是在每个请求之后,甚至不是每个请求都去往完全不同的服务器(这几乎从来不是这种情况)。如果要中断对特定会话的引用,则只需使其无效并取消;否则,只需在该会话上调用flushWithCompletionHandlerresetWithCompletionHandler将会话的堆分配刷新到VM,或者重置以清除堆和VM存储。(另请参阅我的答案here。)

票数 0
EN

Stack Overflow用户

发布于 2017-10-08 13:51:08

finishTasksAndInvalidate在错误的位置调用...completionHandler是用于处理响应的,它与会话无关

下面是正确的代码:

代码语言:javascript
复制
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];
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30106960

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档