3

我只是在编写一些探索性代码来巩固我对 Objective-C 的理解,我遇到了这个我不太明白的例子。我定义了这个方法并运行代码:

- (NSString *)stringMethod
{
    NSString *stringPointer = [[NSString alloc] initWithFormat:@"string inside stringPointer"];
    [stringPointer release];
    [stringPointer release];
    NSLog(@"retain count of stringPointer is %i", [stringPointer retainCount]);
    return stringPointer;
}

运行代码并调用此方法后,我注意到以下几点:

  1. 通常,如果我尝试访问在达到零保留计数后被释放的东西,我会收到 EXC_BAD_ACCESS 错误。在这里,我得到了一个 malloc“双重释放”错误。这是为什么?

  2. 无论我在代码中添加多少行“[stringPointer release]”,NSLog 都会报告保留计数为 1。当我添加更多版本时,我只会得到更多“双重释放”错误。为什么发布声明没有按预期工作?

  3. 尽管我过度释放了 stringPointer 并且收到了一堆“双重释放”错误,但返回值仍然像什么都没发生一样工作(我在主代码中有另一个 NSLog 报告返回值)。程序继续正常运行。再次,有人可以解释为什么会发生这种情况吗?

这些例子是相当微不足道的,但我试图完全掌握正在发生的事情。谢谢!

4

3 回答 3

6

你得到一个双重释放错误,因为你释放了两次并导致两个 dealloc 消息。=P

请记住,仅仅因为您释放并不意味着其内存地址处的数据会立即被销毁。它只是被标记为未使用,因此内核知道,在未来的某个时候,它可以自由地用于另一条数据。在那之前(这在您的应用程序空间中是完全不确定的),数据将保留在那里。

再说一遍:释放(和解除分配)不需要在字节级别立即销毁数据。它只是内核的一个标记。

于 2009-10-07T01:44:29.980 回答
3

这里发生了几件事。首先,释放一个对象并不一定会清除该对象以前占用的任何内存。它只是将其标记为免费。除非您做其他事情导致该内存被重新使用,否则旧数据将一直存在。

在 NSString 的特定情况下,它是一个类集群,这意味着您从 alloc/init 返回的实际类是 NSString 的某个具体子类,而不是 NSString 实例。对于“常量”字符串,这是一个非常轻量级的结构,它只维护一个指向 C 字符串常量的指针。无论您对该字符串制作多少份副本,或者您释放它多少次,都不会影响指向常量 C 字符串的指针的有效性。

在这种情况下尝试检查 [stringPointer 类],以及在可变字符串或实际使用格式字符和参数的格式化字符串的情况下。可能这三个人都会有不同的课程。

于 2009-10-07T01:58:54.843 回答
0

retainCount 总是打印一个可能是由优化引起的 - 当发布通知它将被释放时,没有理由将 retainCount 更新为零(因为此时没有人应该引用该对象)而不是更新 retainCount只是释放它。

于 2009-10-07T01:52:05.303 回答