Objective-C中的内存管理 #导入 int main(int argc,char const*argv[] { SampClass*obj=[[SampClass alloc]init]; [obj释放]; NSLog(@“%i”,[obj重新计数]; 返回0; }

Objective-C中的内存管理 #导入 int main(int argc,char const*argv[] { SampClass*obj=[[SampClass alloc]init]; [obj释放]; NSLog(@“%i”,[obj重新计数]; 返回0; },objective-c,memory-management,Objective C,Memory Management,为什么这会给retainCount 1,而它应该是0,因为对象在您的NSLog调用之前已被释放 我假设发布的实现方式如下所示: #import <Foundation/Foundation.h> int main (int argc, char const *argv[]) { SampClass *obj=[[SampClass alloc] init]; [obj release]; NSLog(@"%i", [obj retainCount]);

为什么这会给retainCount 1,而它应该是0,因为对象在您的NSLog调用之前已被释放

我假设发布的实现方式如下所示:

#import <Foundation/Foundation.h>

int main (int argc, char const *argv[])
{
    SampClass *obj=[[SampClass alloc] init];
    [obj release];
    NSLog(@"%i", [obj retainCount]);
    return 0;
}
如果(重新计算==1)[自解除锁定]; 否则重新计算--; 并且您正在非法访问解除分配的对象

更新: 找到了这些问题,这些问题的答案将进一步启发您:
和。

对象正在解除分配,但一旦对象转到保留计数0,任何方法调用都可能返回过时的值

若编译并在32位上运行,将得到一个错误(消息retainCount发送到释放的对象=0x…)

我猜64位运行时(Leopard上的默认编译选项)收集对象的力度不如32位运行时大,因此您对retainCount的调用不会导致错误

要检查对象是否确实已解除分配,请为SampClass实现解除分配:

if(retainCount==1) [self dealloc]; else retainCount--; 稍后编辑:正如我所怀疑的,在对已发布对象调用方法时,32位和64位之间的行为差异来自运行时,而不是未定义的行为

在32位中,一旦一个类被释放,它的isa指针就被切换到一个特殊的类,该类允许截获释放对象的消息。这在64位中不会发生。 有关资料来源是:


毫无疑问,代码中应该包含什么retainCount,您不应该调用它。依靠释放对象的消息传递结果不是一个好主意。下面是当我复制您的代码,并使用框架的(众多)retain count调试功能之一运行代码时发生的情况:

#if !__OBJC2__ 
    // only clobber isa for non-gc
    anObject->isa = _objc_getFreedObjectClass (); 
#endif

不要调用
retainCount

甚至在调试代码中也没有。尤其是当您试图了解Cocoa的内存管理工作原理时

对象的绝对保留计数不在您的控制范围内。通常,该值会非常意外。框架中可能存在任意数量的缓存、静态分配(如常量NSStrings)或其他内部实现细节,这些都会使对象的保留计数超出您的预期

对象的保留计数应该完全按照增量来考虑。如果导致保留计数增加,则如果要释放对象,则必须在某个位置将其减少。时期故事结束了

试图从绝对角度考虑保留计数只会导致混乱和浪费时间


这一点可以很好地解释。

如果
release
是以这种方式实现的,
obj
可以被解除分配多次。@mouviciel只有在您向它发送过多的发布消息时才可以解除分配,而您不应该这样做(不考虑多线程问题)。我只是想解释为什么SVA的示例打印1。但是,由于对象被解除分配,因此实际上不可能对其内容进行任何假设。这毫无意义。在引用计数代码中不存在“积极收集”的问题,如果您发布,并且这是最终的平衡发布,那么对象将被解除分配。现在不会迟了。@Graham-我无法解释在64位中调用对象上的dealloc,但我仍然可以调用它上的retainCount。我唯一的猜测是,不会对对象调用free,而是将对象添加到某个“free later”池中?它是否保证更改解除分配对象的
isa
指针?可能不会;如果尝试向解除分配的对象发送消息,运行时可能会看到任何旧垃圾,包括该内存位置中对象的最后良好状态。这并不意味着它是正确的、可能的或值得依赖的。未定义的行为需要解释其行为吗?:)未定义已解除分配对象的消息传递行为。
#if !__OBJC2__ 
    // only clobber isa for non-gc
    anObject->isa = _objc_getFreedObjectClass (); 
#endif
heimdall:~ leeg$ pbpaste | sed s/SampClass/NSObject/g > fubar.m
heimdall:~ leeg$ cc -o fubar -framework Foundation fubar.m 
heimdall:~ leeg$ NSZombieEnabled=YES ./fubar
2010-01-07 13:40:10.477 fubar[871:903] *** -[NSObject retainCount]: message sent to deallocated instance 0x10010d8f0
Trace/BPT trap