Swift 重复 URLSession 造成大量内存泄漏
Posted
技术标签:
【中文标题】Swift 重复 URLSession 造成大量内存泄漏【英文标题】:Swift Repetitive URLSession Creates Massive Memory Leaks 【发布时间】:2017-08-21 19:43:43 【问题描述】:我有一个应用程序(部分)向用户显示 Wi-Fi 连接的当前下载速度。它通过打开一个URLSession
并下载一个中等大小 (~10MB) 的文件并测量它所花费的时间来做到这一点。
这是 URLSession 函数:
func testSpeed()
Globals.shared.dlStartTime = Date()
Globals.shared.DownComplete = false
if Globals.shared.currentSSID == ""
Globals.shared.bandwidth = 0
Globals.shared.DownComplete = true
else
let url = URL(string: [HIDDEN])
let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
let task = session.downloadTask(with: url!)
task.resume()
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
Globals.shared.dlFileSize = (Double(totalBytesExpectedToWrite) * 8) / 1000
let progress = (Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)) * 100.0
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ProcessUpdating"), object: nil, userInfo: ["progress" : progress])
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
let elapsed = Double( Date().timeIntervalSince(Globals.shared.dlStartTime))
Globals.shared.bandwidth = Int(Globals.shared.dlFileSize / elapsed)
Globals.shared.DownComplete = true
Globals.shared.dataUse! += (Globals.shared.dlFileSize! / 8000)
session.invalidateAndCancel()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ProcessFinished"), object: nil, userInfo: nil)
正如您可能从委托函数中看出的那样,这一切都存在于与视图控制器分开的类中,以及其他一些小型网络功能,例如获取 IP 和 SSID。代表发布视图控制器观察到的通知。
我的 ViewController 有一个 NSTimer,它每 5 秒回调一次此 URLSession 以重新测试速度(但只有在前一个完成时才运行它)。这是代码:
reloadTimer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(rescanNetwork), userInfo: nil, repeats: true)
调用这个函数:
func backgroundRescan()
if Globals.shared.DownComplete
Networking().testSpeed()
它再次运行 URL Session,当然要检查以确保前一个已经完成。
由于某种原因,我在测试中使用了大量内存,直到应用程序达到 2GB 的内存使用并被控制台输出 Message from debugger: Terminated due to memory issue
终止。这一切都发生在运行应用程序的两分钟内。
我什至在完成委托中添加了session.invalidateAndCancel()
,以拼命尝试清除该记忆。但它没有用。我错过了什么吗?
【问题讨论】:
您确定 Globals.shared.currentSSID 设置为 "" 以外的值吗?如果没有,您将每 5 秒添加一个进程,直到您炸毁为止。 您是否在某处对这些代表进行了强有力的参考?班级是什么样的? 不要每次都实例化一个新的 URLSession。这是 URLSession 的一个已知问题。 Mozahler:这不是真的。除非找到有效的 SSID,否则根本不会调用 URLSession; IE。您实际上已连接到本地网络。尝试和测试,没有问题。 Ssswift:没有强引用。 @Rob 还有其他选择吗?我可以告诉现有会话重新下载相同的文件吗? 纠正我自己,URLSession
问题出现在您重复实例化但从不使其无效的情况下。但是您正在使其无效,因此这不太可能是问题所在。此外,URLSession
泄漏问题是以 kb 为单位衡量的,因此它不太可能是 gb 内存消耗的来源。它一定是别的东西。我会在 Xcode 8 中使用“调试内存图”功能并查找您认为应该释放但没有释放的对象,它会告诉您强引用在哪里(参见 ***.com/a/30993476/1271826)。
【参考方案1】:
正如 Rob 所说,将 URLSessionConfiguration.default 作为变量放入您的类中并使用它。 我遇到了同样的问题,最后我通过使用一个包含我所有通信方法的单一类解决了它,并将 URLSessionConfiguration.default 设置为成员变量。我所有的内存泄漏都解决了。
【讨论】:
我需要更多信息。如果我将任务变量移出函数,我也必须将会话变量移出,因为任务变量使用该会话变量。这一切都很好,但是会话变量让我将delegate: self
参数更改为delegate: self as! URLSessionDelegate
。当我这样做时,代表不再被调用。解决方法?以上是关于Swift 重复 URLSession 造成大量内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
Swift UrlSession 在 UrlSession 中不起作用