【问题标题】:Memory management of Objective-C 2.0Objective-C 2.0 的内存管理
【发布时间】:2012-12-06 05:37:27
【问题描述】:

我是 Objective-C 的初学者。 我正在通过编写简单的命令行代码来研究 Objective-C 中的内存管理。

我的环境如下。

  • Mac OS X Mountain Lion。
  • Xcode4.5

我在下面写了一段代码。

test.m

1     #import <Foundation/Foundation.h>
2     #import <stdio.h>
3     
4     @interface A : NSObject
5     -(void)myprint;
6     @end
7     
8     @implementation A
9     -(void)dealloc {
10       printf("dealloc!!\n");
11       [super dealloc];
12    }
13    
14    -(void)myprint {
15       printf("myprint!!\n");
16    }
17    @end
18    
19    int main(void) {
20    
21       id obj1 = [[[NSObject alloc] init] autorelease];
22       id obj2 = [[A alloc] init];
23    
24       [obj2 release];
25       [obj2 myprint];
26       
27       return 0;
28    }

我使用以下命令构建了这段代码。(构建时没有 ARC 选项)

clang -g -Wall -o main test.m -fno-objc-arc -framework Foundation

构建成功,没有任何警告消息。 结果如下。

dealloc!!
myprint!!

我对这个结果有两个问题。

第一个问题是关于自动释放方法。 我认为这段代码会引发运行时错误,因为 在没有 NSAutoreleasePool 实例的情况下调用 autorelease 方法。 为什么这段代码不会引发运行时错误?

第二个问题是关于 dealloc 方法。 obj2 在调用 dealloc 方法后响应 myprint 方法。 为什么调用dealloc方法后obj2响应myprint方法?

谢谢。

【问题讨论】:

  • 另外——我建议您专注于使用 Xcode 和 Instruments,因为它们更适合您的项目进行扩展。

标签: objective-c ios macos cocoa foundation


【解决方案1】:

第一个问题是关于自动释放方法。我认为这段代码会 引发运行时错误,因为调用 autorelease 方法时没有 NSAutoreleasePool 实例。为什么这段代码不引发运行时 错误?

没有自动释放池,因此,我有点惊讶您在运行时没有看到 no pool in place 警告。不过,这不会是错误,只是发生泄漏的运行时警告。

奇怪。我看到了同样的行为。我会问的。

第二个问题是关于 dealloc 方法。 obj2 响应 myprint 调用 dealloc 方法之后的方法。为什么obj2会响应 调用dealloc方法后的myprint方法?

未定义的行为。 obj2已被释放,但释放并不意味着内存已被清除。

如果您打开 Malloc Scribble(在释放时会在内存上涂鸦),您会看到预期的崩溃:

env MallocScribble=1 ./main
dealloc!!
Segmentation fault: 11

如果你打开僵尸检测,那就更好了:

env NSZombieEnabled=YES ./main
dealloc!!
2012-12-06 08:10:14.580 main[80114:f07] *** -[A myprint]: message sent to deallocated instance 0x7f9b7ac09dd0
Trace/BPT trap: 5

【讨论】:

  • 很好的答案!你的回答对我帮助很大。谢谢。
【解决方案2】:

我相信自动释放池是自动创建的,但我可能错了。至于第二部分,我的理解是 release 告诉一个对象停止被保留,因此不能保证在发布消息之后的任何时候它仍然存在,但它可能会存在一段时间,直到该内存块用于别的东西。基本上你很幸运,如果你多次运行你的代码,你可能并不总是让 obj2 每次都响应 myprint。

【讨论】:

  • no...未创建自动释放池。正如您在我的回答中看到的附加图片。
  • 在这种情况下没有自动释放池。您的其余答案几乎是正确的;该对象已被释放,但释放并不意味着立即重用字节。打开僵尸,你会得到一个错误。
【解决方案3】:

我试过了,你可以看到发生了什么:

如您所见,没有自动释放池...在调试器中显示泄漏。

编辑:

我进行了研究,并了解到该版本正在运行,但系统需要时间来发布,直到调用下一个打印语句。您可以使用以下代码进行检查:

A *obj2 = [[A alloc] init];


NSLog(@"1rc=%ld",[obj2 retainCount]);

[obj2 release];

for (long i=0; i<1000000; i++) {
    for (long j=0; j<10000; j++) {
        ;
    }
}


[obj2 myprint];


for (long i=0; i<1000000; i++) {
    for (long j=0; j<10; j++) {
        ;
    }
}
NSLog(@"myprint again");
[obj2 myprint];

【讨论】:

  • 那些 for 循环是没有意义的。没有线程?完全线性执行,包括对象的释放和释放。您从未定义的行为中得出错误的结论。
  • 我陷入了困境,即使我问了几十个可可资源(同事),也没有人能给出一个很好的理由。所以最后就这样结束了。这个问题仍然悬而未决。这真的是一个很好的学习。我正在等待更正,有证据。
  • 我用 Xcode 尝试了相同的代码。没有出现关于自动释放的警告消息。但是我知道在没有池的情况下调用 autorelease 方法会导致内存泄漏。
  • 太棒了...正如您在随附的屏幕截图中看到的那样:@
  • 我怀疑这可能是命令行问题;该应用程序执行得如此之快,以至于用于输出该警告的机制永远没有机会刷新消息。也许。这只是一个猜测。我应该去阅读源代码。
猜你喜欢
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多