K. Biermann
K. Biermann

Reputation: 1319

NSJSONSerialization.JSONObjectWithData leaks memory

I have a function which uses NSJSONSerialization.JSONObjectWithData, but some memory was not released. So I tracked down where the leak occurred and tested it with the following function:

private func test() {
    for var i = 0; i < 100000; i++ {
        let toParse = NSString(string: "{ \"Test\" : [ \"Super mega long JSON-string which is super long because it should be super long because it is easier to see the differences in memory usage with a super long JSON-string than with a short one.\" ] }").dataUsingEncoding(NSUTF8StringEncoding)!  
        let json = try! NSJSONSerialization.JSONObjectWithData(toParse, options: NSJSONReadingOptions(rawValue: 0))
    }
}   

The memory-usage of my app before I called test() was 11 MB, the memory-usage after was 74.4 MB (even if I did some other things in my app to give the system some time to release the memory)...

Why is json not released?


Mundi pointed me to autoreleasepool which I hadn't tried yet (insert facepalm here)... so I changed the code to:

autoreleasepool {
    self.test()
}

This didn't make any difference, and because Xcode suggested it, I also tried:

autoreleasepool({ () -> () in
    self.test()
})

But this also didn't work...


P.S.: Maybe I should add that I'm using Swift 2.0 in Xcode 7 GM.


P.P.S: The test()-function is called from within a

dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), {
    //... my code ...
    self.test()
})

but this shouldn't make any difference...

Upvotes: 1

Views: 1748

Answers (2)

Mundi
Mundi

Reputation: 80265

As you point out in your question, the app arbitrarily releases the memory, so the fact that it is still not release does not mean it would cause a tight memory condition.

You can try enclosing your test routine in an autoreleasepool, similar to Objective-C.

func test()  {
    autoreleasepool {
       // do the test
    }
}

Upvotes: 1

gnasher729
gnasher729

Reputation: 52538

You are misunderstanding how an autorelease pool works. An autorelease pools keeps hold of allocated memory until the pool is released. Calling a loop 100,000 times inside an autorelease pool means the pool has no chance to release anything, so the memory builds up. Eventually it goes away, when the code has finished running and the autorelease pool is released, but meanwhile your memory usage goes up.

Correct way:

private func test() {
    for var i = 0; i < 100000; i++ {
        autoreleasepool {
            stuff
        }
    }
}

Upvotes: 2

Related Questions