0

私はxcode/cocoa、さらにはobjective-cも初めてなので、私の質問はばかげているかもしれません。フォルダー内のファイルをハッシュするプログラムを作成しようとしています。周りを見回して、NSData オブジェクトを介してファイルをロードし、そのバイトを CC_SHA512 でハッシュする方法を見つけました。

さらにいくつかのファイルをハッシュしようとすると、メモリが不足していることに気付きました。Run -> Performance Tools を使用して、問題を特定できました。私が作成したすべての NSData オブジェクトは、まだメモリ内にあります。release / dealloc を使用して、autorelease と manualy release を試しました。何も機能していません。

私のコンパイラ設定は標準ですが、Objective-C Garbage Collection = required を選択する例外が 1 つあります。

誰かが私が間違っていることを教えてくれるかもしれません。

コードは次のとおりです。

-(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];

}

多分誰かがアイデアを持っています。

事前にあなたに感謝します:) Nubus

4

2 に答える 2

2

いくつかのこと:

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のドキュメントを必ず読む必要があります。すごくすっきりします。

于 2009-11-14T19:12:07.247 に答える
0

MemoryManagement Documentation を読んだ後、私は以前と同じように知っていました。だから私は試行錯誤を始めました。私は保持カウントが0になるまでNSDataオブジェクトを解放するようなことを試みました..そしてそして. 私は実用的な解決策を見つけました。

自分で NSData オブジェクトを初期化し、自動解放に設定する必要がありました (init を呼び出した後、retaincound が 2 で、2 回解放しようとするとクラッシュするため、自分で解放できませんでした)。

ここで私の解決策を説明してください:

-(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 である理由を教えてくれるかもしれません。

于 2009-11-18T12:39:14.917 に答える