使用NSURLSession.downloadTaskWithURL时内存泄漏

Fyg*_*ygo 13 memory memory-leaks ios nsurlsession swift

所以我在与Swift的努力中遇到了另一个障碍.我正在尝试将多个图像加载到图像库中 - 除了一件事以外,一切正常.尽管我清除了图像,但应用程序的内存使用仍在不断增长和增长.在基本上消除了所有代码之后,我发现这是由我的图像加载脚本引起的:

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()
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这段代码基本上没有任何功能.然而,每次我调用它,我的应用程序内存使用量都在增长.如果我注释掉查询,则内存使用量不会改变.

我已经阅读了几个类似的问题,但他们都涉及使用委托.那么,在这种情况下,没有委托,但存在内存问题.有人知道如何消除它以及导致它的原因吗?

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

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

对不起,我还不知道如何使用探查器(在整个iOS爵士乐中非常棒),至少我会附上上面代码生成的探查器截图: 探查

Com*_*ast 29

首先,你必须打电话invalidateAndCancelfinishTasksAndInvalidate在会议上......否则,繁荣,内存泄漏.

Apple的NSURLSession类参考边框中的管理会话部分中说明:

重要信息---会话对象保留对代理的强引用,直到您的应用程序退出或显式使会话无效为止.如果您没有使会话无效,那么您的应用程序会在内存泄漏之前泄漏内存.

是的.

您可能还会考虑以下两种方法:

  • flushWithCompletionHandler:

将cookie和凭据刷新到磁盘,清除瞬态缓存,并确保将来的请求发生在新的TCP连接上.

  • resetWithCompletionHandler:

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

......直接引用上述NSURLSession类参考.

我还应该注意你的会话配置会产生影响:

- (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;
}
Run Code Online (Sandbox Code Playgroud)

如果您不使用[NSURLSession sharedSession]单例,那么一个键就是拥有自己的自定义单例NSObject子类,该子类具有会话作为属性.这样,您的会话对象就会被重用.每个会话都会创建一个与您的应用相关联的SSL缓存,需要10分钟才能清除,如果您为每个请求的新会话分配新内存,那么无论是否持续10分钟,您都会看到SSL缓存的无限内存增长或不是你invalidateAndCancel或冲洗/重置会话.

这是因为安全框架私有地管理SSL缓存,但是为你的应用程序收取它锁定的内存的费用.无论您是否将配置URLCache属性设置为nil,都会发生这种情况.

例如,如果您习惯于说,每秒100个不同的Web请求,并且每个请求使用一个新的NSURLSession对象,那么您每秒创建400k的SSL缓存.(我观察到每个新会话都负责appx.4k的安全框架分配.)10分钟后,这是234兆字节!

因此,请从Apple获取提示并使用具有NSURLSession属性的单例.

请注意,backgroundSessionConfiguration类型保存此SSL缓存的原因以及所有其他缓存内存(如NSURLCache)是因为backgroundSession将其处理委托给现在进行会话的系统,而不是您的应用程序,因此即使您的应用程序是没跑 所以它只是隐藏在你身上......但它就在那里......所以如果那里有巨大的内存增长(即使乐器不会向它显示),我也不会把它放在Apple之外拒绝你的应用程序或终止它的后台会话你,我打赌他们可以看到它).

Apple的文档称backgroundSessionConfigurationURLCache的默认值为零,而不仅仅是零容量.因此,尝试一个短暂的会话或默认会话,然后将其URLCache属性设置为nil,如上例所示.

NSURLRequestReloadIgnoringLocalCacheData如果您不打算使用缓存,那么将NSURLRequest对象的cachePolicy属性设置为也可能是个好主意:D

  • 如果我们使用单例URLSession,那么我们就无法获得每个请求的代理,对吧?单例URLSession将有一个委托.在我的使用中,每个请求(包含在NSOperation中)创建一个URLSession,然后实现其委托来处理进入的数据,接收的数据等.您将如何使用单例URLSession处理该情况? (2认同)

use*_*320 9

我在最近的应用程序中遇到了类似的问题.

在我的情况下,我从API下载了许多图像.对于每个图像,我创建了一个NSURLSessionDownloadTask并将其添加到具有临时配置的NSURLSession.任务完成后,我调用了一个完成块来处理下载的数据.

我添加的每个下载任务都会导致额外的内存(根据Xcode调试器)在之后的任何时候都没有释放.下载大约100张图像时,调试器的内存使用量为~600 MB.下载任务越多,分配和未释放的内存就越多.在任何时候我都没有以任何方式显示或使用图像数据,它只是存储在磁盘上.

试图在仪器中诊断问题并不富有成效.仪器没有泄漏,也没有与下载任务或图像数据相对应的分配.由于我的块等中的保留周期没有内存泄漏,只有在调试器中才有内存螺旋.

经过几个小时的试验和错误,包括:

最后,我将NSURLSession配置从短暂类型切换为背景类型.这要求我不使用完成块来处理图像.我改为在委托中处理它们.这解决了我的问题.将下载任务添加到后台NSURLSession导致内存增长几乎为零,因为下载已启动并处理.

我希望我能更好地理解为什么会这样,但遗憾的是我没有.我已经看到这个问题也出现在其他人身上,并且还没有找到更好的解决方案或解释.

  • 我也有超高内存使用率,我可以确认从defaultSessionConfiguration切换到backgroundSessionConfigurationWithIdentifier最终解决了这个问题. (2认同)