gpt4 book ai didi

memory-leaks - 非ARC项目:NSMutableArray,NSString内存泄漏

转载 作者:行者123 更新时间:2023-12-03 17:13:07 26 4
gpt4 key购买 nike

我们的公司团队致力于现有的应用程序。该项目是非ARC(自动参考计数)。关于释放以下代码的对象存在疑问。

代码1:执行此代码时为什么没有崩溃?

NSMutableArray *arraytest=[[NSMutableArray alloc]init];
for(int i=0;i<100;i++)
{
NSString *str=[NSString stringWithFormat:@"string:%d",i];
[arraytest addObject:str];
}
NSLog(@"arraytest before:%@",arraytest);
[arraytest release];
NSLog(@"arraytest after:%@",arraytest);

相似代码:具有可变副本

代码2:更改后,以下代码在最后一行崩溃。
NSMutableArray *arraytest=[[NSMutableArray alloc]init];
for(int i=0;i<100;i++)
{
NSString *str=[NSString stringWithFormat:@"string:%d",i];
[arraytest addObject:str];
}
NSLog(@"arraytest before:%@",arraytest);
NSMutableArray *copyarray=[arraytest mutableCopy];
[arraytest release];
NSLog(@"copyarray:%@",copyarray);
NSLog(@"arraytest after:%@",arraytest);

为什么这行内存泄漏?

enter image description here

为什么在这一行中出现内存泄漏?

enter image description here

在没有内存泄漏的情况下执行上述代码的正确方法是什么?我们的公司告诉我们,不应在代码上方使用自动发布。

最佳答案

考虑您的第一个示例:

NSMutableArray *arraytest = [[NSMutableArray alloc] init];

// `arraytest` populated ...

NSLog(@"arraytest before:%@", arraytest);
[arraytest release];
NSLog(@"arraytest after:%@", arraytest); // DANGER: referencing dangling pointer!!!
最后一个 NSLog语句非常危险,因为调用 [arraytest release](将数组的保留计数从 +1减少到 0)之后, arraytest指向的对象将被释放,并且 arraytest现在是该释放内存中的 dangling pointer。释放指针后,切勿引用指针。有时看起来好像您可以使用它,但是它并不安全,并且您的应用程序现在可能会意外崩溃。 (但是,如果您使用了僵尸,它将安全地警告您,如果您尝试错误地使用该悬空指针。)

考虑第二个示例:
NSMutableArray *arraytest = [[NSMutableArray alloc] init];

// `arraytest` populated ...

NSLog(@"arraytest before:%@",arraytest);
NSMutableArray *copyarray = [arraytest mutableCopy];
[arraytest release];
NSLog(@"copyarray:%@", copyarray);
NSLog(@"arraytest after:%@", arraytest); // DANGER: referencing dangling pointer!!!
在此示例中,释放后的 NSLog仍然是非常危险的 arraytest,并且使用该悬挂指针很容易崩溃。所以您想要摆脱它。
但是您现在引入了泄漏。释放 arraytest最初指向的对象后,尚未释放 copyarray指向的对象 mutableCopy的结果。因此,此新的 copyarray实例将泄漏。因此,当您创建 arraytest时最初分配的所有那些字符串现在都将由泄漏的 copyarray引用,并且它们也会泄漏。
如果在此例程的末尾添加 [copyarray release],则泄漏数组和泄漏字符串都将得到解决。

现在,考虑您的第三个示例,该示例仅显示在“Instruments”屏幕的最终快照中:
NSMutableArray *arraytest = [[NSMutableArray alloc] init];
for (int i=0; i<100; i++) {
NSString *str = [NSString stringWithFormat:@"string:%d", i];
[arraytest addObject:str];
[str release]; // DANGER: released `str` whose ownership was never transferred to you!!!
}
NSLog(@"arraytest before:%@",arraytest);
NSMutableArray *copyarray=[arraytest mutableCopy];
[arraytest release];
NSLog(@"copyarray:%@",copyarray);
NSLog(@"arraytest after:%@",arraytest); // DANGER: referencing dangling pointer!!!
在最后一个示例中,我们通过过度释放刚添加到数组中的字符串来使问题复杂化。因此,您创建了一个自动释放对象(当自动释放池耗尽时,保留计数实际上为零),将其添加到数组中(将其有效保留计数增加到 +1),然后释放了 str(将保留计数减少到 +0)排干水池)。
该应用程序现在处于不稳定状态,因为该数组现在正在引用耗尽自动释放池时可以释放的对象,最终导致一个悬空指针数组。更糟糕的是,如果该数组本身被正确释放,那么所有这些字符串都将被过度释放。
而且,当然,如上面第二个示例中所讨论的,仍然存在阵列泄漏的情况。但是,如果您确实释放了此 copyarray,那么所有这些字符串都将被过度释放。

在这一点上可能无需多说,但是消除此泄漏的方法是简单地释放 copyarray:
NSMutableArray *arraytest = [[NSMutableArray alloc] init];
for (int i=0; i<100; i++) {
NSString *str = [NSString stringWithFormat:@"string:%d", i];
[arraytest addObject:str];
}
NSLog(@"arraytest before:%@", arraytest);
NSMutableArray *copyarray = [arraytest mutableCopy];
[arraytest release];
NSLog(@"copyarray:%@", copyarray);
[copyarray release];
这遵循 Basic Memory Management Rules,即您有责任通过从以 releaseallocnewcopy开头的方法接收对象来对拥有的那些对象调用 mutableCopy

一些结束语:
  • 如果要使用手动引用计数,建议您经常使用Xcode的静态分析器(Shift + command + B或Xcode的“产品”菜单上的“分析”)。在识别手动引用计数内存问题方面令人惊讶的出色。工具是有用的,但是正如上面第三个示例所示,您很容易得出错误的结论(例如,“gee,我需要释放所有这些字符串”)。静态分析仪会为您指出其中的一些问题。
    最重要的是,在继续进行操作之前,请务必确保您已从静态分析仪中获得了健康的清单。当分析仪可以准确地告诉您问题是什么时,尝试进行反向工程毫无意义。
  • 我建议不要从一个特定的悬空指针不会使您的应用程序崩溃的事实中得出任何结论,而另一个则不会。这只是不可预测的。如果打开僵尸(仅出于开发/测试目的而不是生产应用程序而临时启用),这将引起您注意引用先前已释放对象的任何尝试。
  • 我注意到您在测试中使用的是NSString。您应该知道NSString具有内部存储器优化功能,可以产生非标准行为。我会警惕在这类实验中使用NSString
    不要误会我的意思:如果您遵循所有Basic Memory Management RulesNSString将正常运行。但是,如果您在故意不遵循这些内存管理规则的情况下尝试检查会导致何种类型的错误/崩溃,请注意NSString可能会产生误导。
  • 不用说,使用ARC将大大简化您的生活。有关更多信息,请参见Transitioning to ARC Release Notes
  • 关于memory-leaks - 非ARC项目:NSMutableArray,NSString内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40424391/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com