antfarm antfarm - 1 month ago 11
Swift Question

NSExpression memory leak?

I want to evaluate dynamically generated mathematical expressions using

NSExpression
. When I run the simple program below, memory consumption quickly sums up to 1 GB and more.

Am I obviously leaking memory or is there anything wrong with the way I am using
NSExpression
?

#!/usr/bin/env swift

import Foundation

for _ in 1...100 {

let expressionString = "((x - y) * ((x * x) - (((x - y) * -1) - y))) + (x * (((x * (y - x)) - x) * -1))"
let expression = NSExpression(format: expressionString)

for x in 0 ..< 320 {
for y in 0 ..< 320 {
let result = expression.expressionValue(with: ["x" : x, "y": y], context: nil) as! Double
}
}
}


In the real program, of course, I create a new
expressionString
for every iteration of the outer loop.

Answer

The memory does not leak, but Foundation methods like expressionValue() can return an "autoreleased" object (and may even create more autoreleased objects internally). These are only released when the current autorelease pool ends (e.g. when execution returns to the main event loop in a Cocoa/Cocoa Touch application).

A command-line application does not have an autorelease pool by default. You can add one to control the lifetime of autoreleased objects. For example:

for x in 0 ..< 320 {
    autoreleasepool {
        for y in 0 ..< 320 {
            let result = expression.expressionValue(with: ["x" : x, "y": y], context: nil) as! Double
        }
    }
}

You'll have to figure out on which loop level to put the pool (to balance memory consumption vs. execution time).

See also Is it necessary to use autoreleasepool in a Swift program?, and Using Autorelease Pool Blocks in the "Advanced Memory Management Programming Guide".