Reputation: 3587
In my application (an OS X app), I send approximately 5,000 URL requests in a short timespan, to retrieve JSON objects from a server. I send 50 requests simultaneously, wait for all of them to finish, and then send another batch of 50. But I'm having some memory management issues...
By the time all of the requests have completed (~2 minutes), my app has increased its memory usage by about 250MB, and this memory never gets released. I'm using NSURLSession/dataTaskWithURL
to fetch the data, and in order to troubleshoot I've removed ALL code from the completion handler - it simply fires the request and discards the response. Here's an example:
func fetchData() {
let config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
// Also tried .defaultSessionConfiguration()
config.URLCache = nil
config.HTTPCookieAcceptPolicy = .Never
config.HTTPCookieStorage = nil
let session = NSURLSession(configuration: config)
let query = session.dataTaskWithURL(myURL) { (data, response, error) -> Void in
session.invalidateAndCancel()
// Normally call a completion handler here too
}
query.resume()
}
Note that I'm disabling all cache and cookies, as well as calling invalidateAndCancel()
when the request has finished. I've also tried using the standard sharedSession()
, but none of this makes any difference - the memory usage always climbs rapidly and stays high permanently.
This is a big problem, because my app needs to send these requests periodically and the memory just climbs higher with each cycle - eventually reaching several GBs of RAM. It should also be noted that my program slows to a crawl once the memory usage has reached this point.
Does anybody know why NSURLSession
might be retaining so much memory? Profiling with Instruments doesn't reveal any memory leaks, so I'm pretty stumped here. Any help or suggestions would be greatly appreciated.
Upvotes: 3
Views: 1203
Reputation: 437442
Two things:
Since you're using NSURLSession
, make sure you're not instantiating a new one for each of those 5000 requests. Instantiated one and then reuse that. Perhaps try using NSURLSession.sharedSession()
instead.
I've seen modest memory consumption per session, and if you have an extraordinary number of sessions, it can add up
You say that you ran Instruments to look for leaks. Nowadays, you'll rarely find anything as egregious as that. But you also should look for strong reference cycles and the like like by analyzing allocations or generations between two points in time and identify what accounts for the 250mb, then see where it's allocated, etc.
See WWDC videos, such as 2013's Fixing Memory Issues or 2012's iOS App Performance: Memory (and ignore the fact that iOS is in the title; as many of these principles apply equally well on MacOS), which will illustrate how to diagnose such issues.
Upvotes: 2
Reputation: 165
Have you tried setting
Config = nil
Query = nil
Session = nil
[session finishTasksAndInvalidate]
At end? But personally I'd be more concerned as to why you need to make 5000 requests? Seems like bad design to me...
Upvotes: 0