0

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

我的环境如下。

  • Mac OS X 山狮。
  • Xcode4.5

我在下面写了一个代码。

测试.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方法?

谢谢。

4

3 回答 3

2

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

于 2012-12-06T05:46:04.470 回答
2

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

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

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

第二个问题是关于 dealloc 方法。obj2 在调用 dealloc 方法后响应 myprint 方法。为什么调用dealloc方法后obj2响应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
于 2012-12-06T16:10:40.380 回答
1

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

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

在此处输入图像描述

编辑:

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

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];
于 2012-12-06T05:48:41.660 回答