使用[NSKeyedUnarchiver decodeObjectForKey]泄漏内存
-
05-07-2019 - |
题
每次调用此方法时,我的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];
}
解决方案
我建议更换这一行:
venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];
使用:
ListClassName *decodedList = [decoder decodeObjectForKey:inKey];
self.venueIOList = decodedList;
这使得 decodingList
的内存管理变得清晰。使用访问器方法分配实例变量被认为是最佳实践(init方法除外)。在您当前的实现中,如果您再次在同一个对象上调用 readVenueArchiveFile:
,将泄漏(如果 decodingList
已经泄漏有价值)。此外,你可以将复制逻辑放在你的访问器方法中而忘记它,而不是每次分配一个新值时都要记住mutableCopy(假设有一个很好的理由来制作一个可变拷贝?)。
其他提示
减少峰值内存占用
通常,最好避免生成自动释放的对象。
[本段的大部分修订自这个问题。]既然你通常(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的内存管理编程指南。
不要担心保留计数,担心方法内的平衡。假设 venueIOList
是一个实例变量,你在这个方法中所做的事情看起来是正确的。
稍微扩展一下我的答案:unarchiver可能会在unarchive操作期间保留您的数据,然后在完成后发送数据 -autorelease
而不是 -release 代码>。由于这不是你所做的事情,所以你不必关心。
与refcount相关的内存管理启示的最终来源仍然是,IMO,“来自Stepwise的Hold Me,Use Me,Free Me“。
你的代码是正确的;没有内存泄漏。
theData = [NSData dataWithContentsOfFile:inFile];
相当于
theData = [[[NSData alloc] initWithContentsOfFile:inFile] autorelease];
此时,数据的引用计数为1(如果更少,则将其取消分配)。引用计数将在未来的某个时间点由自动释放池自动递减。
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
解码器对象保持对数据的引用,该引用将其引用计数增加到2。
在方法返回后,自动释放池将此值减少为1.如果在此方法结束时释放Data,引用计数将变为0,对象将被释放,并且当您尝试使用时应用程序将崩溃用它。