Memory Leak When Using Nsurlsession.Downloadtaskwithurl

NSURLSession Memory Leaks occur when using web services in IOS

After rereading the URL Loading System Programming Guide it turns that I was setting the NSURLSession property to nil too early.

Instead, I need to set the NSURLSession property to nil AFTER I receive the delegate message URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error, which makes sense. Luckily, it was a minor mistake.

E.g.

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
{
if (error)
{

#ifdef DEBUG
NSLog(@"[GPPhotoRequest] Session Invalidation: %@", [error description]);
#endif

}

if ([session isEqual:_session])
{
[self cleanupSession];
}
}

NSURLSession HTTP/2 memory leak

From apple doc:

The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you don’t invalidate the session, your app leaks memory until it exits.

Also looking at your project https://github.com/upyun/swift-sdk/tree/testleak you need to call finishTasksAndInvalidate() after sessionTask.resume() since you are creating session per request

Swift 3 URLSession memory leak

Shared URL session has a credential storage for cookies and other "browser" stuff. Since it's shared it is a singleton which will live forever in your application. Instruments interprets this as a leak.

Advice: repeat the action several times before you look for leaks.

Also, quite likely the self reference in your callback holds onto your view controller while your request is still pending. Use weak self at the block start to break the cycle. But that totally depends on your design. It got me at least in a few cases.

I also want to refer to this answer: https://stackoverflow.com/a/35757989/3351794

NSURLSession: method dataTaskWithRequest never reach completion callback on lengthy responses

When fetching large resources, you should use download task. A data task will attempt to load the entire response in a single NSData object. Loading a large asset in memory at the same time is not only inefficient, but if it is extraordinarily large, can cause problems.

A download task is well suited for these tasks, because it will stream the asset to a temporary file for you, reducing the peak memory usage. (Admittedly, you can manually achieve the same with data task with delegate pattern, but download tasks do this for you.)

You said:

I saw that there's an alternative method in NSURLSession dedicated for downloading files called downloadTaskWithRequest but it doesn't have an async completion block.

Two observations:

  1. There is a rendition, dataTaskWithRequest:completionHandler:, that has a completion block:

    NSURLSession* session = [NSURLSession sharedSession];
    NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    ...
    }];
    [task resume];

    Note, I would advise using sharedSession if you are not setting a delegate, or otherwise customizing your NSURLSession. You do not want to instantiate NSURLSession objects unnecessarily. And if you really must instantiate a NSURLSession, re-use it for subsequent tasks and/or make sure to call finishTasksAndInvalidate after submitting the last task for that session, or else the NSURLSession will leak. And, if you instantiate your own NSURLSession, you do not have to instantiate your own operation queue, as it will, by default, create a serial queue for you if you do not supply an operation queue.

  2. The rendition without a block parameter, downloadTaskWithURL:, works, too. All you need to do is to specify a delegate for your NSURLSession and then and implement URLSession:downloadTask:didFinishDownloadingToURL:.

    The reason I suggest this is that, often, when we are downloading very large assets (especially over cellular), we realize that the users may want to leave our app and let the download complete in the background. In those situations, we would use a background NSURLSessionConfiguration. And when using background sessions, you must use this delegate-based approach. So, if you think you might eventually adopt background sessions for long downloads, then adopting a delegate-based approach now is not a bad idea.

    For more information, see Downloading Files in the Background.



Related Topics



Leave a reply



Submit