目标c - 这是内存泄漏吗(使用 NSArray 和 NSCopying)



我在代码中尝试了一些东西,以查看对内存利用率的影响。我想找出环路内的线路是否泄漏。运行此循环会使利用率达到 100MB,并且不会再次下降。这是否表示内存泄漏?如果是这样,为什么?(我正在使用 ARC)

for (i = 0; i < 10000000; i++)
    {
        self.accounts = [[NSArray alloc] initWithArray:[_dal accounts] copyItems:YES];
    }

(accounts是一个AccountSummary对象的数组,它像这样实现NSCoping:名称城市状态电话都是NSStrings,isLocal是BOOL)

- (id)copyWithZone:(NSZone *)zone {
    AccountSummary *newAccount = [[AccountSummary allocWithZone:zone] init];
    newAccount.name = [self.name copyWithZone:zone];
    newAccount.city = [self.city copyWithZone:zone];
    newAccount.state = [self.state copyWithZone:zone];
    newAccount.phone = [self.phone copyWithZone:zone];
    newAccount.isLocal = self.isLocal;
    return newAccount;
}

我可以看到这里没有泄漏。但是,会有相当多的峰值内存使用。

应该在逻辑上释放内存的事物的确切行为各不相同。很多时候,它不是释放内存,而是自动释放。(对于MRR,曾经有一种称为autorelease的方法。当您自动发布某些内容时,它并没有真正发布,而是计划在代码完成后发布,因为它返回到主事件循环。

如果其中一部分是自动释放的——我的猜测是属性分配是自动释放的,因为自动释放比硬释放"更安全"——那么在下一次自动释放池刷新之前,内存不会被释放。主线程上的代码有一个由操作系统本身设置的自动发布池,因此每次返回主事件循环时,所有自动发布的内容都会被清除。在这里,这可能意味着所有 10,000,000 个副本都保留在内存中,直到您返回到主事件循环。的,这会让真正的设备崩溃。:)

(这是假设你在主线程上;如果你不在,你甚至可能没有设置自相关系池,这意味着你可能会得到泄漏。但我认为在这种情况下,您会收到控制台警告,因此您已经对该走哪条路有了提示。

您可以使用@autoreleasepool来减少此峰值内存使用量:

for (i = 0; i < 10000000; i++) @autoreleasepool {
    self.accounts = [[NSArray alloc] initWithArray:[_dal accounts] copyItems:YES];
}

现在将发生的情况是,计划稍后在循环的每次迭代中释放的内存实际上将在循环的每次迭代中释放。这应该可以解决您的直接问题。

也就是说,除了检查行为之外,我无法想象你为什么要这样做。如果是这样的话,这不太可能是你的核心问题。

假设你的核心问题是泄漏,那么使用ARC,你并不是在寻找泄漏。您正在寻找循环引用。这意味着您的答案可能位于代码中的其他位置。如果您确定是自己的帐户而不是 dsl 的帐户泄漏,请寻找自己是否参与循环循环。

另外,请记住,在NSString上调用copyWithZone:可能不会复制字符串。(无需复制只读字符串,因为无法更改只读字符串。两个"副本"可以是同一个对象。因此,如果您只泄漏字符串,它们可能与原始对象相关联。

在循环中创建大量对象时,应在自动释放池中创建

@autoreleasepool {
    for (i = 0; i < 10000000; i++) {
        self.accounts = [[NSArray alloc] initWithArray:[_dal accounts] copyItems:YES];
    }
}

或者,更有可能在现实世界中...

for (i = 0; i < 10000000; i++) {
    @autoreleasepool {
        self.accounts = [[NSArray alloc] initWithArray:[_dal accounts] copyItems:YES];
    }
}

最新更新