David Chouinard
David Chouinard

Reputation: 6866

Memory leak: steady increase in memory usage with simple device motion logging

Consider this simple Swift code that logs device motion data to a CSV file on disk.

let motionManager = CMMotionManager() 
var handle: NSFileHandle? = nil

override func viewDidLoad() {
    super.viewDidLoad()

    let documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
    let file = documents.stringByAppendingPathComponent("/data.csv")

    NSFileManager.defaultManager().createFileAtPath(file, contents: nil, attributes: nil)
    handle = NSFileHandle(forUpdatingAtPath: file)

    motionManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.currentQueue(), withHandler: {(data, error) in
        let data_points = [data.timestamp, data.attitude.roll, data.attitude.pitch, data.attitude.yaw, data.userAcceleration.x,
            data.userAcceleration.y, data.userAcceleration.z, data.rotationRate.x, data.rotationRate.y, data.rotationRate.z]

        let line = ",".join(data_points.map { $0.description }) + "\n"
        let encoded = line.dataUsingEncoding(NSUTF8StringEncoding)!

        self.handle!.writeData(encoded)
    })
}

I've been stuck on this for days. There appears to be a memory leak, as memory consumption steadily increases until the OS suspends the app for exceeding resources.

Memory usage

It's critical that this app be able to run for long periods without interruption. Some notes:

Any pointers? I've tried to use Instruments, but I don't have the skills the use it effectively. It seems that the exploding memory usage is caused by __NSOperationInternal. Here's a sample Instruments trace.

Thank you.

Upvotes: 2

Views: 2016

Answers (1)

matt
matt

Reputation: 536028

First, see this answer of mine:

https://stackoverflow.com/a/28566113/341994

You should not be looking at the Memory graphs in the debugger; believe only what Instruments tells you. Debug builds and Release builds are memory-managed very differently in Swift.

Second, if there is still trouble, try wrapping the interior of your handler in an autoreleasepool closure. I do not expect that that would make a difference, however (as this is not a loop), and I do not expect that it will be necessary, as I suspect that using Instruments will reveal that there was never any problem in the first place. However, the autoreleasepool call will make sure that autoreleased objects are not given a chance to accumulate.

Upvotes: 3

Related Questions