aranha
aranha

Reputation: 43

Can't find memory leak in Swift app

I'm trying to learn Swift and so I wrote a little test application to that end. It just gives the total size of items in a directory, recursing into subdirectories to accumulate the total size of the their contents. The application works, but the memory usage just grows and grows while it runs. I had expected the memory usage to increase as the recursion got deeper and decrease when a recursive call returns. Instead, the memory usage just constantly climbs. Instruments doesn't identify any leaks. I've tried a few tips I've found in various google results, including:

re-using the default NSFileManager not re-using the default NSFileManager but creating a new one for each recursive call avoiding String interpolation

Nothing seems to make any difference. I had thought that Swift would clean up objects as their reference count reached zero.

This is the code in its entirety in its current state:

import Foundation

func sizeOfContents(path: String) -> UInt64
{
    let subManager = NSFileManager()
    var totalSize: UInt64 = 0;
    var isDir: ObjCBool = false
    if subManager.fileExistsAtPath(path, isDirectory: &isDir)
    {
        if !isDir.boolValue
        {
            var error: NSError? = nil
            let attributes: NSDictionary? = subManager.attributesOfItemAtPath(path, error: &error)
            let size: UInt64? = attributes?.fileSize()
            totalSize += size!
        }
        else
        {
            var error: NSError? = nil
            if let subContents = subManager.contentsOfDirectoryAtPath(path, error: &error)
            {
                for subItem in subContents
                {
                    var subName = subItem as String
                    subName = path + "/" + subName
                    totalSize += sizeOfContents(subName)
                }


            }
        }
    }

    return totalSize
}

let manager = NSFileManager.defaultManager()
var rootPath = "/Applications/"
if let contents = manager.contentsOfDirectoryAtPath(rootPath, error: nil)
{
    for item in contents
    {
        let itemName = item as String
        var isDir: ObjCBool = false
        print("item: " + (rootPath + itemName))
        if manager.fileExistsAtPath(rootPath + itemName, isDirectory: &isDir)
        {
            if !isDir.boolValue
            {
                var error: NSError? = nil
                let attributes: NSDictionary? = manager.attributesOfItemAtPath(rootPath + itemName, error: &error)
                let size: UInt64? = attributes?.fileSize()
                println("\t\(size!)")
            }
            else
            {
                if(itemName != "Volumes")
                {
                    let size = sizeOfContents(rootPath + itemName)
                    println("\t\(size)")
                }
            }
        }
    }
}

Upvotes: 3

Views: 980

Answers (1)

zaph
zaph

Reputation: 112857

You need to add an autoreleasepool in the loop, possibly around the recursive call. Since it is a tight loop the idle loop is not getting a change to release the temp memory allocations.

example:

...
autoreleasepool {
    totalSize += sizeOfContents(subName)
}
...

Upvotes: 2

Related Questions