使用文件管理器迭代目录占用大量内存

Posted

技术标签:

【中文标题】使用文件管理器迭代目录占用大量内存【英文标题】:iterate dirs using filemanager take up quite a lot memory 【发布时间】:2013-07-09 03:15:35 【问题描述】:

我正在使用NSFileManagerenumeratorAtPath方法来计算特定目录下的文件大小。

NSString *iterDir = @"/path/to/dir/";
NSFileManager *fm = [[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath:iterDir];

NSString *file;
BOOL isDir;
long long fileSize = 0;
while (file = [dirEnum nextObject]) 
    @autoreleasepool 
        file = [iterDir stringByAppendingString:file];
        if ([fm fileExistsAtPath:file isDirectory:&isDir]) 
            if (!isDir) 
                NSError *error;
                NSDictionary *attributes = [fm attributesOfItemAtPath:file error:&error];
                if (!error) 
                    fileSize += [attributes[@"NSFileSize"] doubleValue];
                
            
        
    

NSLog(@"fileSize:%lld", fileSize);

结果是这样的:

有时是这样的:

内存是干什么用的?为什么连在外面加个@autoreleasepool都没效果?

【问题讨论】:

使用 Instruments 找出导致它的原因。然后回来报告,因为我很好奇。 【参考方案1】:

我无法让您的示例按照提供的方式运行,即使替换为有效的目录路径也是如此。您的代码有一些问题。这是您需要进行的一些更改。一个是这一行:

file = [iterDir stringByAppendingString:file];

真的应该改成:

file = [iterDir stringByAppendingPathComponent:file];

后者要安全得多,因为无论您的目录路径是否以/ 结尾,它都会正确附加路径。 (在我的情况下,您的原始文件失败了,因为我使用 [@"~/Desktop" stringByExpandingTildeInPath] 来获取我的目录路径;这会产生一个没有尾随 / 的路径。)

然后在你的循环中,你在堆栈上分配一个未初始化的变量error,通过引用传递它,然后询问它是否是nil。这是一个错误的问题,因为除非方法返回 nil(或 NO,取决于方法),否则无法保证 error 的值。相反,您应该询问 attributes 是否为 nil,并将 NULL 传递给 error,因为否则您似乎对此不感兴趣。所以总结一下,改变这个:

NSError *error;
NSDictionary *attributes = [fm attributesOfItemAtPath:file error:&error];
if (!error) 

到这里:

NSDictionary *attributes = [fm attributesOfItemAtPath:file error:NULL];
if (attributes != nil) 

我保证,解决第二个问题意味着您的结果将更加一致。同时,当我运行代码时,我得到的结果看起来可能是 NSLog() 语句中的有效值。

无所谓,您也可以在循环中使用快速枚举。而不是:

while (file = [dirEnum nextObject]) 

你可以改用:

for (file in dirEnum) 

现在回答您最初的问题。您分配的内存变大的原因是您的包含文件名的字符串被分配到您的 @autoreleasepool 指令范围之外的主自动释放池中,它们将一直坐在那里直到该池清空。但是,在循环中使用自己的自动释放池仍然是一件好事。

【讨论】:

感谢 4 条优化建议,它们真的很有帮助。但仍然无法修复/解释内存问题。不能跑?您可以提供像/Users/yourname/Desktop 这样的绝对路径。它应该做的工作。 绝对路径可以工作,但是当使用其他方法生成没有尾部斜杠的路径时,例如我使用的方法呢? 当然stringByAppendingPathComponent: 有效,但对结果没有影响。

以上是关于使用文件管理器迭代目录占用大量内存的主要内容,如果未能解决你的问题,请参考以下文章

python dask to_parquet 占用大量内存

C#管理大量耗时的线程,内存占用严重

记一次linux磁盘清理 - 已经删除的文件占用了大量磁盘空间

Lsass.exe进程占用大量内存

进程过多,占用大量内存,如何分析

电脑使用过程中,内存占用率过高好吗?大概在70%到85%之间!