使用[NSKeyedUnarchiver decodeObjectForKey]泄漏内存

时间:2008-10-03 21:49:07

标签: objective-c cocoa

每次调用此方法时,我的NSMutableData都在泄漏,我无法弄清楚如何插入它。解码器分配和初始化后,数据的保留计数增加1,我不明白为什么。我在方法结束时遇到了保留计数2并试图释放它会导致应用程序崩溃。

- (void)readVenueArchiveFile:(NSString *)inFile key:(NSString *)inKey
{
    NSMutableData *theData;
    NSKeyedUnarchiver *decoder;


    theData = [NSData dataWithContentsOfFile:inFile];

    decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];

    venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];

    [decoder finishDecoding];

    [decoder release];
}

5 个答案:

答案 0 :(得分:4)

减少峰值内存占用

通常,最好避免生成自动释放的对象。

[本段的大部分修改自this question。]由于您通常(1)无法直接控制其生命周期,因此自动释放的对象可能会持续相当长的时间,并且会不必要地增加您的内存占用量。应用。虽然在桌面上这个可能没有什么后果,但在更受限制的平台上,这可能是一个重要问题。因此,在所有平台上,特别是在更受约束的平台上,强烈建议您不要使用会导致自动释放对象的方法,而是鼓励使用alloc / init模式。

我建议更换一下:

theData = [NSData dataWithContentsOfFile:inFile];

使用:

theData = [[NSData alloc] initWithContentsOfFile:inFile];

然后在方法结束时添加:

[theData release];

这意味着在方法退出之前将释放theData。 你最终应该:

- (void)readVenueArchiveFile:(NSString *)inFile key:(NSString *)inKey
{
    NSMutableData *theData;
    NSKeyedUnarchiver *decoder;

    theData = [[NSData alloc] initWithContentsOfFile:inFile];
    decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
    ListClassName *decodedList = [decoder decodeObjectForKey:inKey];
    self.venueIOList = decodedList;
    [decoder finishDecoding];
    [decoder release];
    [theData release];

}

这使内存管理语义清晰,并尽快回收内存。

(1)您可以使用自己的本地自动释放池来控制。有关详情,请参阅Apple's Memory Management Programming Guide

答案 1 :(得分:3)

我建议更换这一行:

venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];

使用:

ListClassName *decodedList = [decoder decodeObjectForKey:inKey];
self.venueIOList = decodedList;

这使得decodedList的内存管理变得清晰。使用访问器方法分配实例变量被认为是最佳实践(init方法除外)。在您当前的实现中,如果您第二次在同一个对象上调用readVenueArchiveFile:,则泄漏(如果decodedList已有值,则会如此)。此外,你可以将复制逻辑放在你的访问器方法中而忘记它,而不是每次分配一个新值时都要记住mutableCopy(假设有一个很好的理由来制作一个可变拷贝?)。

答案 2 :(得分:2)

不要担心保留计数,担心方法内的平衡。假设venueIOList是一个实例变量,那么您在此方法中所做的事情看起来是正确的。

稍微扩展一下我的答案:unarchiver可能会在取消归档操作期间保留您的数据,然后在数据-autorelease完成后发送而不是-release。由于这不是所做的事情,所以不必关心。

答案 3 :(得分:1)

与Refcount相关的内存管理启示的最终来源仍然是IMO,来自Stepwise的"Hold Me, Use Me, Free Me"

答案 4 :(得分:0)

你的代码是正确的;没有内存泄漏。

theData = [NSData dataWithContentsOfFile:inFile];

相当于

theData = [[[NSData alloc] initWithContentsOfFile:inFile] autorelease];

此时,数据的引用计数为1(如果更少,则将其取消分配)。引用计数将在未来的某个时间点由自动释放池自动递减。

decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];

解码器对象保持对数据的引用,该引用将其引用计数增加到2。

在方法返回后,自动释放池将此值减少为1.如果在此方法结束时释放Data,引用计数将变为0,对象将被释放,并且当您尝试使用时应用程序将崩溃用它。