Does anybody have an idea why does the following code use an absurd 4.75 GB of memory?
Is there any better way to loop for all files in the filesystem? (I'm trying to find the largest files on the drive)
let filemanager:FileManager = FileManager()
let root = "/"
let files = filemanager.enumerator(atPath: root)
while let element = files?.nextObject() {
// do nothing
}
Note: there are 400k files on my filesystem (nothing special). The code is sequential, so in theory it shouldn't even depend on the number of files.
I paused it with the memory graph, and it shows an absurd number of NSConcreteData instances, allocated from fileSystemRepresentation(withPath:).
That documentation page notes that it's a pointer that's only good for the current autorelease pool. That suggests a solution: we just have to get the nextObject()
call into its own autorelease pool.
This program, for example, stays steady at 11.0 MB:
var done = false
while !done {
autoreleasepool {
let element = files?.nextObject()
done = (element == nil)
// do nothing
}
}
It looks like Swift's while let
syntax puts the binding in the autorelease pool of the while loop's context, so each element remains retained until the entire loop completes.
By forcing the enumerator's object into our own autorelease pool, we can make sure it's not retained during subsequent iterations.
EDIT: Since autoreleasepool
is just a func, I could have written this much more concisely:
while let element = autoreleasepool(invoking: { files?.nextObject() }) {
// do nothing
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With