【问题标题】:Leaks (instrument) reports leaks in autoreleased objects泄漏(仪器)报告自动释放对象中的泄漏
【发布时间】:2011-03-09 06:53:01
【问题描述】:

更新:此泄漏已得到解决。如果您遇到类似的泄漏并且您的应用程序是多线程的,那么您很可能从后台线程进行 UIKit 调用;利用例如[NSThread performSelectorOnMainThread:] 将 UIKit 调用路由到主线程,这是 唯一允许调用的地方

我最近一直在对我当前的项目运行 Leaks 以查找泄漏,并且我不断遇到这些“泄漏”,据我所知,这些“泄漏”并不是真正的泄漏。根据 Leaks 的说法,以下代码直接取自项目,有两个漏洞:

- (NSArray *)areaForIndex:(int)index 
{
    NSMutableArray *a = [NSMutableArray arrayWithArray:
        [world  retrieveNeighborsForIndex:index]]; // leak 1
    [a insertObject:[references objectAtIndex:index] atIndex:0];
    return [NSArray arrayWithArray:a]; // leak 2
}

如果我将第一行更改为:(参见更新 2-3)

,泄漏 1 就会消失

如果我将最后一行更改为:

,Leak 2 就会消失
    return a;

不幸的是,泄漏 1 无法做到这一点,因为我将一个不可变数组转换为一个可变数组。尽管如此,无论如何,arrayWithArray 应该自动释放,所以据我所知,它不应该泄漏任何东西。任何想法为什么会发生这种情况?

更新:我已经在设备和模拟器上对此进行了测试。两者都有泄漏。然而,在模拟器上我得到了一些关于这个泄漏的额外信息:

泄露的历史如下:

# | Category | Event Type  | Timestamp | RefCt |  Address  | Size | Responsible Library | Responsible Caller
--+----------+-------------+
0 | CFArray  | Malloc      | 00:09.598 |     1 | 0x474f6d0 |   48 | asynchro            | -[muddyGrid areaForIndex:]
1 | CFArray  | Autorelease | 00:09.598 |       | 0x474f6d0 |    0 | Foundation          | NSRecordAllocationEvent
2 | CFArray  | CFRetain    | 00:09.598 |     2 | 0x474f7d0 |    0 | Foundation          | -[NSCFArray retain]
3 | CFArray  | CFRelease   | 00:09.611 |     1 | 0x474f7d0 |    0 | Foundation          | NSPopAutoreleasePool

从上面我可以看出,自动释放的数组以某种方式保留了两次,然后自动释放,保留计数为 1。不知道在哪里或为什么......

更新 2 和 3:我尝试将泄漏 1 的行更改为:

    NSMutableArray *a = [[[NSMutableArray alloc] initWithArray:
        [world retrieveNeighborsForIndex:index]] autorelease];

我认为这消除了泄漏,但最终并没有。所以我还是一头雾水。

【问题讨论】:

  • 你是在设备上测试还是在模拟器上测试?
  • 目前仅在设备上。但你是对的,我会在模拟器上进行测试,看看结果如何并更新。
  • 更新了上面的描述,包括我在模拟器上尝试的结果。谢谢指点! :)

标签: iphone xcode ipad instruments memory-leaks


【解决方案1】:

滑稽地,当我用我的代码解决了一堆其他问题时,这个问题自行解决了。

主要是,代码中有很多地方是在主线程之外进行 UI 更新的,这是一个很大的禁忌。这些其他不相关的问题之一肯定触发了上述代码中的内存泄漏,因为它不再报告任何泄漏(我现在有 0 个泄漏),尽管我没有修改任何代码。

【讨论】:

    【解决方案2】:

    retrieveNeighborsForIndex 返回什么?

    这个方法的结果有没有可能被保留(不是自动释放)?

    【讨论】:

    • 它返回[neighbors allObjects],其中neighbors是一个NSMutableSet,其中包含许多对象(9-12)。
    【解决方案3】:

    arrayWithArray 保留您存储到可变数组中的对象。 http://www.iphonedevsdk.com/forum/iphone-sdk-development/14285-nsmutablearray-arraywitharray-does-add-retain.html

    我建议释放它,或者更安全地创建具有自动释放属性集的对象。当为索引调用检索邻居时,使这些对象自动释放,当 nsmutable 数组被释放时它们将被释放

    编辑: 在跟踪内存错误时我可能会添加的一个提示是启用僵尸,并检查对象的引用计数。然后,您可以确定哪些未发布,它应该使您的跟踪更容易。此链接将向您展示如何设置您的 xcode 项目以启用僵尸:cocoadev.com/index.pl?NSZombieEnabled

    【讨论】:

    • 可以,但是arrayWithArray:返回的数组本身是自动释放的,所以自己释放可能会导致崩溃。也就是说,返回可变数组本身可能是安全的,因为您正在创建它并以相同的方法返回它,没有隐藏的副作用。
    • 这适用于泄漏 2(这就是我现在正在做的事情),但它不能解决泄漏 1,我正在使用 arrayWithArray 将不可变数组转换为可变数组,因为我在返回之前需要添加它。
    • 顺便说一句,我的回答是给 Wevah; Shadow 的正确之处在于 arrayWithArray: 保留了数组中的对象,但它本身不包含在内,不应该被释放也不应该自动释放。
    • 您的不可变数组不在自动释放池中。尝试将 autorelease 属性添加到该数组
    • Shadow:也许我遗漏了一些东西,但它没有被保留在任何地方(它作为自动释放的对象返回)- [NSSet allObjects] 不返回保留的对象。
    猜你喜欢
    • 2021-08-13
    • 2011-11-02
    • 2012-01-01
    • 2011-04-27
    • 2011-03-09
    • 2011-11-03
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    相关资源
    最近更新 更多