You have to call invalidateAndCancel
or finishTasksAndInvalidate
on the session, first of all... or else, boom, memory leak.
Apple's NSURLSession Class Reference states in Managing the Session section in a sidebox:
IMPORTANT
--- The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you do not
invalidate the session, your app leaks memory until it exits.
So yeah.
You might also consider these two methods:
- flushWithCompletionHandler:
Flushes cookies and credentials to disk, clears transient caches, and
ensures that future requests occur on a new TCP connection.
- resetWithCompletionHandler:
Empties all cookies, caches and credential stores, removes disk files,
flushes in-progress downloads to disk, and ensures that future
requests occur on a new socket.
... as directly quoted from the aforementioned NSURLSession Class Reference.
I should also note that your session config can have an effect:
- (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;
}
One key, if you are not using the [NSURLSession sharedSession]
singleton, is for you to have your own custom singleton NSObject subclass that has a session as a property. That way, your session object gets reused. Every session will create an SSL cache associated to your app, which takes 10 minutes to clear, if you allocate new memory for a new session with each request, then you will see unbounded memory growth from SSL caches that persist for 10 minutes regardless of whether or not you invalidateAndCancel
or flush/reset the session.
That's because Security framework privately manages the SSL cache, but charges your app for the memory it locks up. This will happen whether or not you set your configuration's URLCache
property to nil.
For example, if you are in the habit of doing say, 100 different web requests per second, and each one uses a new NSURLSession object, then you're creating something like 400k of SSL cache per second. (I have observed that each new session is responsible for appx. 4k of Security framework allocations.) After 10 minutes, that's 234 megabytes!
So take a cue from Apple and use a singleton with an NSURLSession property.
Note that the reason the backgroundSessionConfiguration
type saves you this SSL cache memory, and all other cache memory like NSURLCache, is because a backgroundSession delegates its handling to the system who now makes the session, not your app, so it can happen even if your app is not running. So it's just hidden from you... but it's there... so I would not put it past Apple to reject your app or terminate its background sessions if there is huge memory growth back there (even though Instruments won't show it to you, I bet they can see it).
Apple's docs say that backgroundSessionConfiguration
has a nil default value for the URLCache, not just a zero capacity. So try an ephemeral session or default session and then set its URLCache property to nil, as in my example above.
It's probably also a good idea to set your NSURLRequest object's cachePolicy property to NSURLRequestReloadIgnoringLocalCacheData
also, if you are not going to have a cache :D