在Objective C中为NSObject存储的保留计数在哪里

Ed *_*rty 9 memory-management objective-c

我很好奇内部保留/释放的工作方式.在脸上,好像有涉及到的每个实例的整数NSObject,这被增加,当你调用下降-retain-release分别.

但是看看NSObject,它所拥有的唯一实例变量是isa变量,用于确定其类类型.

那么存储单个对象的保留计数在哪里?并不是说我会用它来捣乱,而只是为了我自己的启发.

它是存储在一起NSObject,但隐藏在一些Objective C实现细节中?如果是这样,那对我来说似乎是一个糟糕的设计.一个应该能够创建他们自己的根类和处理自己的保留/释放以类似的方式计算(不,这是一个好主意-人们必须有一个非常好的理由不使用NSObject).

rob*_*off 15

保留计数的存储位置取决于使用的运行时和类实现.

对于Apple的Objective-C运行时,您可以通过深入了解Objective-C运行时的源代码来解决很多问题.

例如,如果您正在使用ARC(我认为即使您不使用),大多数对象的引用计数也会存储在哈希表中.看看中的_objc_rootRetain功能runtime/objc-arr.mm.我不知道为什么他们这样做.也许这是一种将保留计数保持在一起以获得更好的缓存行为的方法(这在ARC下很重要,因为ARC比非ARC代码通常更频繁地调整保留计数).

但是,某些类会覆盖retain相关方法并将保留计数存储在其他位置.例如,在调试内存泄漏时,我发现这样CALayer做.不使用运行时的正常保留计数机制,而是CALayer将其保留计数存储在私有C++实现对象中.这是相当令人沮丧的,因为这意味着仪器分配工具不记录CALayer对象的保留和释放.


Ric*_*III 7

我们不确切知道数据的存储方式,但我们可以排除一些选项:

私人执行变量

我们可以排除这一点,因为当我们遍历NSObject类的iVars时,我们只看到一个:isa,如此程序所示:

id object = [NSObject new];
Class meta = object->isa;

printf("class name: %s\n", class_getName(meta));

unsigned count;
Ivar *ivars = class_copyIvarList(meta, &count);

for (int i = 0; i < count; i++) {
    printf("iVar: %s\n", ivar_getName(ivars[i]));
}

free(ivars);
Run Code Online (Sandbox Code Playgroud)

请注意,甚至私有实现属性都存在于metdata类中.

私有财产

我们也可以对此进行排除,因为甚至私有属性都在类元数据中公开,如下例所示,NSObject该类没有属性:

id object = [NSObject new];    
Class meta = object->isa;

printf("class name: %s\n", class_getName(meta));

objc_property_t *properties = class_copyPropertyList(meta, &count);

for (int i = 0; i < count; i++) {
    printf("property: %s\n", property_getName(properties[i]));
}
Run Code Online (Sandbox Code Playgroud)

相关对象

这个很难排除,因为没有直接的方法来获取所有相关对象的列表.但是,由于关联对象的概念是非常新的,并且引用计数已经永远存在,我说这不太可能.

CoreFoundation struct-mangling

这是我最好的猜测.当您创建NSObject时,它是幕后的结构.这就是说实际的NSObject数据表示是这样的:

typedef struct CFObject {
    int retainCount;
    id isa;
} *CFObjectRef;
Run Code Online (Sandbox Code Playgroud)

然后,创建对象时:

id object_createInstance(...)
{
    CFObjectRef object = malloc(sizeof(struct CFObject));

    ...

    return (id) (object + sizeof(object->retainCount));
}

int object_retainCount(id self)
{
    CFObjectRef asObject = (CFObjectRef) (self - sizeof(asObject->retainCount));
    return asObject->retainCount;
}
Run Code Online (Sandbox Code Playgroud)

然而,我无法验证这一点,因为还有许多其他方法可以完成(例如,对象的整数映射).