Can't find memory leak in Swift app
I'm trying to learn Swift and so I wrote a little test app for that. It just gives the total size of the items in a directory, recursively into subdirectories to copy the total size of their content. The app works, but memory usage just goes up and up as it runs. I expected the memory usage to increase as the recursion gets deeper and decrease when the recursive call returns. Instead, memory usage just goes up constantly. Instruments do not identify leaks. I've tried a few tips I've found in various google results, including:
reuse the default NSFileManager do not reuse the default NSFileManager, but create a new one for each recursive call avoiding string interpolation
Nothing matters. I thought Swift would clear objects as their countdown reaches zero.
This is the complete code as it stands:
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)")
}
}
}
}
}
You need to add autoreleasepool in a loop, perhaps around a recursive call. Since it is a closed loop, the wait loop does not receive any changes to free temporary memory allocations.
Example:
...
autoreleasepool {
totalSize += sizeOfContents(subName)
}
...