objective-c释放时间和不良访问

objective-c释放时间和不良访问,objective-c,autorelease,Objective C,Autorelease,我有一个这样的代码,在MRC中,我相信调用[t2 description]会使应用程序崩溃 坏消息,t已经发布了,但是当我测试这个的时候,有时候还可以,有时候崩溃了, 所以问题来了,发布操作是异步的吗 另一个问题是,如果有两个指针指向同一个自动释放对象, 当自动释放池耗尽时,它与[t释放]和[t2释放]非常相似,这会是一个问题吗 NSObject * t = [[NSObject alloc] init]; NSObject * t2 = t; [t release]; [t2 descrip

我有一个这样的代码,在MRC中,我相信调用[t2 description]会使应用程序崩溃 坏消息,t已经发布了,但是当我测试这个的时候,有时候还可以,有时候崩溃了, 所以问题来了,发布操作是异步的吗

另一个问题是,如果有两个指针指向同一个自动释放对象, 当自动释放池耗尽时,它与[t释放]和[t2释放]非常相似,这会是一个问题吗

NSObject * t = [[NSObject alloc] init];
NSObject * t2 = t;

[t release];
[t2 description];

我猜第一个问题可能与Runloop有关:当您调用release API时,系统向Runloop发送一条消息,然后Runloop找到函数并执行它,而不是立即执行

第二个问题,当自动释放池耗尽时,自动释放对象的保留计数将为-1,如果保留计数变为0,则自动释放对象将被释放。在object-C中,您可以向nil对象发送消息


希望能帮助您……

发布操作可能会异步工作,这取决于实现。我认为实际上它不是异步的。
但有时框架会额外引用一个实例。这个引用可能只会在运行循环的下一次迭代后才被释放,或者只有在收到内存警告时才被释放,甚至可能永远不会被释放。在引擎盖下,系统真的试图优化内存操作。例如,字符串文字永远不会被释放,使用这些字符串文字创建的不可变字符串实际上指向相同的字符串文字。但这是一个实现细节,您不能依赖它

基本上有两条规则:

向对象发送最后一条
release
消息后,不得访问该对象。最后,我指的是从您自己的代码的角度来看。e、 g:

NSMutableString *str = [[NSMutableString alloc] initWithString:@"Foo"]; // 1 reference from alloc
NSLog("%@", str); // good
[str retain]; // reference count + 1 = 2 total
NSLog("%@", str); // good 
[str release]; // reference count - 1 = 1 total
NSLog("%@", str); // good 
[str release]; // reference count -1 = 0 total. Object should be considered deallocated
NSLog("%@", str); // bad. It is no longer safe to access the object
如果发送
autorelease
,则在离开autorelease池的当前作用域之前,您可以安全地访问该对象(如果您不使用自己的池,通常直到您从方法返回为止)。e、 g:

而且,您不能自动释放比您获取的引用更多的引用。因为如上所述,autorelease基本上会将
release
消息的发送延迟到稍后的时间。它将被发送。autorelease中的auto并不意味着系统检查对象以确定是否需要释放


请记住,这些消息发送到对象,而不是变量

您的代码:

NSObject * t = [[NSObject alloc] init];
NSObject * t2 = t;

[t release];
[t2 description];
在内存管理方面,这等于:

NSObject * t = [[NSObject alloc] init];

[t release];
[t description];
当您执行这些操作时,您应该发送一条保留消息,并在以后(自动)释放它。我通常使用自动释放。例如:

NSObject * t = [[NSObject alloc] init];
NSObject * t2 = [[t retain] autorelease];

[t release];
[t2 description]; // totally safe to do
或者,为了更清楚地了解发生了什么,我们可以将代码拆分为更多行:

NSObject * t = [[NSObject alloc] init]; // ref = 1 
NSObject * t2 = t;  // no change in ref count
[t retain];  // ref + 1 = 2
[t autorelease]; // later: ref - 1 = current ref: 2 (-1 scheduled for later)

[t release]; // ref - 1 = 1 (-1 later)
[t2 description]; // totally safe to do because you still have a reference

return;
// end of method

// when the autorelease pool is drained the system sends the scheduled release
// the object is no longer referenced and gets deallocated. 


有一点补充说明:学习这些东西很好,但在高效代码中,最好启用ARC。ARC非常稳定、快速,在复杂的应用程序中,它将提高您自己代码的稳定性。你必须写更少的代码,调试更少。所以,帮你自己一个忙,在生产中使用ARC。

向可能解除分配的实例发送消息是未定义的行为。未定义意味着无法保证会发生什么。它可能会崩溃。它似乎工作正常。它可能会让Hello Kitty出现在你的电脑上。不管怎样

通常,当一些动态分配的内存被释放时,内存中的字节保持不变。内存块仅标记为可供使用。因此,通常情况下,在新的内容覆盖内存之前,内存位置仍将“看起来”像以前对象有效时的位置,因此,如果您尝试将其当作真实对象使用,某些类型的操作似乎仍然“成功”并不罕见。同样,这取决于很多环境条件,比如内存是如何分配的,对象是否恰好被分配到旧对象所在的位置,特定的系统,等等,而您不能依赖它

所以问题来了,发布操作是异步的吗


不,释放是同步的。但发行版并不一定要解除对它的分配。你不知道在这个对象还活着的时候,什么东西可能已经保留并自动释放了它。允许任何API保留和自动释放对象。在这种情况下,不太可能有人自动删除它。

指向自动删除对象的指针不会变为零。它是一个“悬空指针”,使用该指针向对象发送消息可能会导致崩溃。第一个指针不在运行循环中,第二个指针不会变为零
NSObject * t = [[NSObject alloc] init]; // ref = 1 
NSObject * t2 = t;  // no change in ref count
[t retain];  // ref + 1 = 2
[t autorelease]; // later: ref - 1 = current ref: 2 (-1 scheduled for later)

[t release]; // ref - 1 = 1 (-1 later)
[t2 description]; // totally safe to do because you still have a reference

return;
// end of method

// when the autorelease pool is drained the system sends the scheduled release
// the object is no longer referenced and gets deallocated.