Objective c 使用[NSKeyedUnachiver decodeObjectForKey]的内存泄漏
每次我调用这个方法时,我的NSMutableData都在泄漏,我不知道如何插入它。在解码器被分配和初始化之后,数据的保留计数增加了1,我不知道为什么。我在方法的末尾遇到了一个2的保留计数,试图释放它会导致应用程序崩溃Objective c 使用[NSKeyedUnachiver decodeObjectForKey]的内存泄漏,objective-c,cocoa,Objective C,Cocoa,每次我调用这个方法时,我的NSMutableData都在泄漏,我不知道如何插入它。在解码器被分配和初始化之后,数据的保留计数增加了1,我不知道为什么。我在方法的末尾遇到了一个2的保留计数,试图释放它会导致应用程序崩溃 - (void)readVenueArchiveFile:(NSString *)inFile key:(NSString *)inKey { NSMutableData *theData; NSKeyedUnarchiver *decoder; the
- (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
是一个实例变量,那么您在这个方法中所做的看起来是正确的
让我对我的答案进行一点扩展:unarchiver可能会在unarchive操作期间保留您的数据,然后在完成后发送数据
-autorelease
,而不是-release
。因为这不是你做过的事情,也不是你必须关心的事情。我认为,与refcount相关的内存管理启示的最终来源仍然是逐步的。我建议替换这一行:
venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];
与:
这使得
decodedList
的内存管理变得清晰。使用访问器方法(init方法除外)分配实例变量被认为是最佳实践。在当前的实现中,如果在同一对象上再次调用readVenueArchiveFile:
,则将泄漏(如果decodedList
已经有值,则会泄漏)。此外,您可以将复制逻辑放在访问器方法中,然后忘记它,而不必在每次分配新值时都记住mutableCopy(假设有很好的理由创建一个mutableCopy?)。您的代码是正确的;没有内存泄漏
theData = [NSData dataWithContentsOfFile:inFile];
相当于
theData = [[[NSData alloc] initWithContentsOfFile:inFile] autorelease];
此时,数据的引用计数为1(如果小于1,则将取消分配)。自动释放池将在将来的某个时间自动减少引用计数
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
解码器对象保留对数据的引用,该引用将其引用计数增加到2
方法返回后,自动释放池将该值递减为1。如果在此方法结束时释放数据,引用计数将变为0,对象将被释放,并且当您尝试使用它时,应用程序将崩溃。减少峰值内存占用
通常,避免生成自动释放对象被认为是最佳实践
[本段大部分修改自.]由于您通常(1)无法直接控制其生命周期,自动释放的对象可能会持续较长时间,并不必要地增加应用程序的内存占用。虽然在桌面上,这可能影响不大,但在更受约束的平台上,这可能是一个重大问题。因此,在所有平台上,尤其是在约束更严格的平台上,强烈建议您不要使用会导致自动释放对象的方法,而应使用alloc/init模式
我建议更换这个:
theData = [NSData dataWithContentsOfFile:inFile];
与:
然后在方法末尾添加:
[theData release];
这意味着在方法退出之前,数据将被释放。
您应该以以下方式结束:
- (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) 您可以使用自己的本地自动释放池进行控制。有关这方面的更多信息,请参阅。这令人困惑。1.在给出的代码中,无法引用方法之外的数据。2.自动释放池不会在方法返回后减少保留计数,因此,如果您可以引用该方法之外的数据,则只有在池已耗尽时才会崩溃。您的分析不正确。1.数据被传递到保留它的解码器对象。2.是的,自动释放池会在方法返回后减少引用计数。在给人们提供错误的建议之前,先了解一下Cocoa。不清楚为什么(1)与在方法之外是否可以访问数据有关。(2)问题不在于自动释放池是否减少引用计数,而是在方法返回后,它不会这样做,而是(通常)在事件循环的末尾。因此,如果您能够在方法之外访问数据,那么您可能不会崩溃!如果一个自动释放的对象可以在声明它的方法执行期间的任何时候被释放,那么它将不可用,因为您永远不知道它是否已经被释放。想想看!
[theData release];
- (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];