内存泄漏时使用NSURLSession.downloadTaskWithURL

所以我在斯威夫特的努力中遇到了另一个障碍。 我正在尝试将多个图像加载到图像库中 – 除了一件事情之外,所有的工作都很好。 尽pipe我清除了图像,但应用程序的内存使用仍在不断增长和增长。 基本上所有的代码基本上,我发现这是由我的图像加载脚本引起的:

func loadImageWithIndex(index: Int) { let imageURL = promotions[index].imageURL let url = NSURL(string: imageURL)! let urlSession = NSURLSession.sharedSession() let query = urlSession.downloadTaskWithURL(url, completionHandler: { location, response, error -> Void in }) query.resume() } 

正如你所看到的,这段代码现在基本上什么都没有。 然而每次我打电话时,我的应用程序内存使用量都在增长。 如果我注释掉查询,内存使用情况不会改变。

我已经阅读了几个类似的问题,但都涉及使用一个代表。 那么,在这种情况下,没有代表还有内存问题。 有谁知道如何消除它,是什么造成的?

编辑:这是一个完整的testing类。 似乎内存只在图像可以加载时才会增长,就像指向图像的指针永远保存在内存中一样。 当图像没有find时,没有任何反应,内存使用率保持低。 也许有些提示如何清理这些指针?

 import UIKit class ViewController: UIViewController { override func viewDidLoad() { //memory usage: approx. 23MB with 1 load according to the debug navigator //loadImage() //memory usage approx 130MB with the cycle below according to the debug navigator for i in 1...50 { loadImage() } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func loadImage() { let imageURL = "http://mama-beach.com/mama2/wp-content/uploads/2013/07/photodune-4088822-beauty-beach-and-limestone-rocks-l.jpg" //random image from the internet let url = NSURL(string: imageURL)! let urlSession = NSURLSession.sharedSession() let query = urlSession.downloadTaskWithURL(url, completionHandler: { location, response, error -> Void in //there is nothing in here }) query.resume() } } 

我很抱歉,我还不知道如何使用profiler(在整个iOS的爵士乐中是非常小的),至less我会附上上面代码生成的profiler截图: 探查

你必须在会话中调用invalidateAndCancelfinishTasksAndInvalidate ,首先…否则,繁荣,内存泄漏。

苹果的NSURLSession类参考状态在边框的 pipe理会话部分:

重要—会话对象保持对委托的强引用,直到你的应用程序退出或显式使会话失效。 如果您不会使会话无效,那么您的应用程序会泄漏内存,直到退出。

嗯是的。

你也可以考虑这两种方法:

  • flushWithCompletionHandler:

刷新cookies和凭证到磁盘,清除临时caching,并确保将来的请求发生在新的TCP连接上。

  • resetWithCompletionHandler:

清空所有的Cookie,caching和凭证存储,删除磁盘文件,将正在进行的下载刷新到磁盘,并确保将来的请求在新套接字上发生。

…直接引用上述NSURLSession类参考。

我也应该注意到你的会话configuration可以有一个效果:

 - (void)setupSession { NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; config.URLCache = nil; config.timeoutIntervalForRequest = 20.0; config.URLCredentialStorage = nil; config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData; self.defaultSession = [NSURLSession sessionWithConfiguration:config]; config = nil; } 

一个关键是,如果你不使用[NSURLSession sharedSession]单例,你有你自己的具有会话作为属性的自定义单例NSObject子类。 这样,你的会话对象被重用。 每个会话都会创build一个与您的应用关联的SSLcaching ,如果您为每个请求的新会话分配新的内存,则需要10分钟的时间才能清除 ,然后您将看到SSLcaching的无限增长,持续10分钟,无论是否或者不是你invalidateAndCancelinvalidateAndCancel或刷新/重置会话。

这是因为安全框架私下pipe理SSLcaching,但是会为您的应用程序收取locking的内存。 无论是否将configuration的URLCache属性设置为零,都会发生这种情况。

例如,如果您习惯于说每秒100个不同的Web请求,并且每个请求都使用一个新的NSURLSession对象,那么您每秒就会创build一个类似于400k的SSLcaching。 (我注意到,每个新会话都负责安全框架分配的约4k).10分钟后,这是234兆字节!

所以从苹果公司获得一个提示,并使用具有NSURLSession属性的单例。

请注意, backgroundSessionConfigurationtypes为您保存此SSLcaching内存的原因以及所有其他caching内存(如NSURLCache)的原因是,backgroundSession将其处理委托给现在进行会话的系统,而不是您的应用程序,所以即使您的应用程序没有运行。 所以它只是隐藏在你的身边……但是它在那里…所以我不会放过苹果,拒绝你的应用程序,或者如果在那里有巨大的内存增长就终止它的后台会话(即使Instruments不会显示它你,我打赌他们可以看到它)。

苹果公司的文档说backgroundSessionConfiguration对URLCache有一个零缺省值,而不仅仅是一个零容量。 因此,请尝试一个短暂的会话或默认会话,然后将其URLCache属性设置为零,如上例所示。

如果你不打算有一个caching,也可以把你的NSURLRequest对象的cachePolicy属性设置为NSURLRequestReloadIgnoringLocalCacheData :D

我在最近的一个应用程序遇到类似的问题。

在我的情况下,我正在从API下载一些图像。 对于每个图像,我创build一个NSURLSessionDownloadTask并将其添加到具有短暂configuration的NSURLSession。 当任务完成时,我调用一个完成块来处理下载的数据。

我添加的每个下载任务都会导致额外的内存被分配(根据Xcodedebugging器),此后任何时候都不会释放这些内存。 当下载大约100个图像时,debugging器的内存使用量为〜600 MB。 下载任务越多,分配的内存越多,而不是释放。 我从来没有以任何方式显示或使用图像数据,只是将其存储到磁盘。

试图用仪器诊断这个问题并不富有成效。 仪器显示没有泄漏,没有分配相应的下载任务或图像数据。 没有由于我的块或类似的保留周期内存泄漏,只有在debugging器内存螺旋。

经过几个小时的反复试验,包括:

  • 下载完成块设置为零的图像(以确保在块中没有保留周期)。

  • 评论我的代码的各个部分,以确保分配正好发生在'[downloadTask resume]'被调用时。

  • 将会话的URLCache设置为nil和大小为0的caching。根据以下url : http : //www.drdobbs.com/architecture-and-design/memory-leaks-in-ios-7/240168600

  • 将NSURLSessionconfiguration更改为默认configuration。

最后我把我的NSURLSessionconfiguration从一个短暂的types切换到背景types。 这要求我不使用完成块来处理图像。 我在代表处处理它们。 这为我解决了这个问题。 将下载任务添加到后台NSURLSession在启动和处理下载时导致内存增长几乎为零。

我希望我能更好地理解为什么会出现这种情况,但不幸的是我不这样做。 我也看到这个问题也为别人着想,还没有find更好的解决办法或解释。

@ user3847320 ANSWER应该是被接受的! 另外ValNet AFNetWorking:

 NSURLSessionConfiguration* configurationSession = [NSURLSessionConfiguration backgroundSessionConfiguration:@"backgroundSession"]; _currentSessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configurationSession]; NSURLSessionDownloadTask * downloadTask = [_currentSessionManager downloadTaskWithRequest:...];