为什么FileManager.enumerator使用大量的内存?

ada*_*ily 4 macos memory-leaks nsfilemanager swift

有谁知道为什么下面的代码使用4.75 GB的荒谬内存?

有没有更好的方法循环文件系统中的所有文件?(我正在尝试在驱动器上找到最大的文件)

let filemanager:FileManager = FileManager()
let root = "/"
let files = filemanager.enumerator(atPath: root)
while let element = files?.nextObject() {
    // do nothing
}
Run Code Online (Sandbox Code Playgroud)

注意:我的文件系统上有40万个文件(没什么特别的)。代码是顺序的,因此从理论上讲,它甚至不应该依赖于文件数。

Sss*_*ift 5

我用内存图暂停了它,它显示了从fileSystemRepresentation(withPath :)分配的大量NSConcreteData实例。

该文档页面指出,它是仅对当前自动释放池有用的指针。这建议一个解决方案:我们只需要将nextObject()调用放入其自己的自动释放池即可。

例如,此程序稳定在11.0 MB:

var done = false
while !done {
    autoreleasepool {
        let element = files?.nextObject()
        done = (element == nil)

        // do nothing
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来Swift的while let语法将绑定放入while循环上下文的自动释放池中,因此每个元素都将保留到整个循环完成为止。

通过将枚举器的对象强制进入我们自己的自动释放池,我们可以确保在后续迭代期间不保留该对象。

编辑:既然autoreleasepool只是一个函数,我本可以写得更简洁一些:

while let element = autoreleasepool(invoking: { files?.nextObject() }) {
    // do nothing
}
Run Code Online (Sandbox Code Playgroud)