【问题标题】:Can't free memory of NSData object无法释放 NSData 对象的内存
【发布时间】:2010-12-16 15:38:53
【问题描述】:

我是 xcode / cocoa 甚至是 Objective-c 的新手,因此我的问题可能很愚蠢。我正在尝试编写一个程序来散列文件夹中的文件。我环顾四周,找到了一种通过 NSData 对象加载文件的方法,然后使用 CC_SHA512 对其字节进行哈希处理。

如果我尝试对更多文件进行哈希处理,我注意到我的内存已用完。使用 Run -> Performance Tools 我可以查明我的问题。我创建的所有 NSData 对象仍在内存中。我尝试使用 release/dealloc 自动释放和手动释放。什么都没有。

我的编译器设置是标准的,但有一个例外,我选择 Objective-C 垃圾收集 = 必需。

也许有人可以告诉我我做错了什么。

代码如下:

-(FileHash*) hashFileByName :(NSString*) filePath{

    //NSData* inputData = [inputStr dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(filePath);
    NSData* inputData = [[NSData dataWithContentsOfFile:filePath] autorelease];
    unsigned char outputData[CC_SHA512_DIGEST_LENGTH];
    CC_SHA512([inputData bytes], [inputData length], outputData);


    NSMutableString* hashStr = [NSMutableString string];
    int i = 0;
    for (i = 0; i < CC_SHA512_DIGEST_LENGTH; ++i)
        [hashStr appendFormat:@"%02x", outputData[i]];


    //NSLog(@"%@ hash : %@",filePath,hashStr);

    FileHash *hash = [[[FileHash alloc]init]autorelease];
    [hash setFileHash:hashStr];
    [hash setFilePath:filePath];
    [inputdata release];
    [inputdata dealloc];
    return hash;    
}

-(NSMutableArray*) hashFilesInDirectory:(NSString*) pathToDirectory:(Boolean) recursive : (IBOutlet id) Status : (Boolean*) BreakOperation{

    NSGarbageCollector *collect = [NSGarbageCollector defaultCollector];

    NSMutableArray *files;
        files = [[self listFilesOnlyRecursive:pathToDirectory] autorelease];

    NSMutableArray *hashes = [[[NSMutableArray alloc]init]autorelease];

    for (NSString *file in files) {

        [hashes addObject: [self hashFileByName:file]]; 
        [collect collectExhaustively];
    }


    return hashes;
}

-(NSMutableArray*) listFilesOnlyRecursive : (NSString*) startDir {

    NSMutableArray *filelist = [[[NSMutableArray alloc] init]autorelease];

    //Inhalt eines Verzeichnisses auflisten (unterverzeichnisse werden ignoriert
    NSFileManager *manager = [[NSFileManager defaultManager]autorelease];

    NSDirectoryEnumerator *enumerator = [manager enumeratorAtPath:startDir];
    int count = 0;
    id file;
    while (file = [enumerator nextObject])
    {

        //      file = [[[[startDir stringByAppendingString:@"/"]autorelease] stringByAppendingString:file] autorelease
        //              ];
        file = [NSString stringWithFormat:@"%@/%@",startDir,file];
        BOOL isDirectory=NO;
        [[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory];
        if (!isDirectory){
            [filelist addObject:file];
            //printf("\n:%s:\n",[file UTF8String]);
            count++;
        }


    }
    NSLog(@"Es waren %i files",count);
    return filelist;
}

这一切都是由

开始的
int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //return NSApplicationMain(argc,  (const char **) argv);
    MemoryLeakTest *test = [[[MemoryLeakTest alloc]init]autorelease];
    [test hashFilesInDirectory:@"/huge directory/" :YES :nil :nil];
    [pool drain];
    [pool release];
    [pool dealloc];

}

也许有人有想法。

比你提前:) 努布斯

【问题讨论】:

    标签: xcode memory garbage-collection nsdata memory-leaks


    【解决方案1】:

    有几点:

    NSData* inputData = [[NSData dataWithContentsOfFile:filePath] autorelease];
    

    如果您想在当前方法执行之后保留它,则必须保留它(这有点过于简单,但对于您的示例来说是合理的)。由于dataWithContentsOfFile: 不包含alloc、copy 或new,除非您明确保留它,否则您不负责释放它。鉴于您只在函数中本地使用它,您不需要保留它。因此,只需使用以下内容,不要对其调用 release/autorelease 或 dealloc:

    NSData* inputData = [NSData dataWithContentsOfFile:filePath];
    

    此外,您永远不会手动释放事物。只需根据需要释放/自动释放它们。将根据需要调用 dealloc。

    [inputData dealloc]; // don't do this explicitly
    

    您肯定需要阅读Cocoa Memory Management document。它会清理很多。

    【讨论】:

    • 您好,感谢您的链接。文档指出,如果我使用方便的方法,我不必像你说的那样使用发布。 NSData 对象不在 hashFileByName 函数之外使用。我真的不知道如何摆脱 NSData 对象。 (我没有通过Documentation jet)有没有办法强制移除这样的对象?谢谢
    • 方便的方法给你一个自动释放的对象。这意味着(假设它的保留计数为零)它将在下一个自动释放收集点在内存中回收。如果你想更明确一点,你需要 alloc/init/release。
    【解决方案2】:

    阅读 MemoryManagement 文档后,我知道的和以前一样多。所以我开始尝试和错误。我尝试了诸如释放 NSData 对象之类的方法,直到保留计数为 0 .. and and and 。比我找到了一个可行的解决方案。

    我必须自己初始化 NSData 对象,并将其设置为自动释放(我无法自己释放它,因为在我调用 init 后,retaincound 为 2,尝试释放它 2 次会导致崩溃

    blabla 我的解决方案:

    -(FileHash*) hashFileByName :(NSString*) filePath{
    
        NSAutoreleasePool *innerpool = [[NSAutoreleasePool alloc]init];
    
        //NSData* inputData = [inputStr dataUsingEncoding:NSUTF8StringEncoding];
        NSData* inputData = [[[NSData alloc]initWithContentsOfFile:filePath] autorelease];
        unsigned char outputData[CC_SHA512_DIGEST_LENGTH];
        CC_SHA512([inputData bytes], [inputData length], outputData);
    
    
        NSMutableString* hashStr = [NSMutableString string];
        int i = 0;
        for (i = 0; i < CC_SHA512_DIGEST_LENGTH; ++i)
            [hashStr appendFormat:@"%02x", outputData[i]];
    
    
    
        [innerpool drain];
    
        //NSLog(@"%@ hash : %@",filePath,hashStr);
    
        FileHash *hash = [[[FileHash alloc]init]autorelease];
        [hash setFileHash:hashStr];
        [hash setFilePath:filePath];
    
        return hash;    
    }
    

    我希望这会对某人有所帮助:)

    感谢您的回答。

    ps:也许有人可以告诉我为什么我不能自己释放它,或者为什么保留计数为 2。

    【讨论】:

      猜你喜欢
      • 2012-05-22
      • 1970-01-01
      • 2013-07-30
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多