objc_object解读
栏目: Objective-C · 发布时间: 5年前
内容简介:Objective-C是面向对象的语言.面向对象语言有一句话说:"万物皆对象",这个"对象"从哪里来呢?下面从Runtime源码实现来进一步查看.一. objc_object声明相关首先我们先看runtime.h文件,这个文件相当于Runtime对外部提供的接口文件.包含方法,成员变量,分类,属性等结构声明,也包含了objc_class的完整声明.当我们使用Xcode创建一个类的时候一般都是调用的这里.
Objective-C是面向对象的语言.面向对象语言有一句话说:"万物皆对象",这个"对象"从哪里来呢?下面从Runtime源码实现来进一步查看.
一. objc_object声明相关
首先我们先看runtime.h文件,这个文件相当于Runtime对外部提供的接口文件.包含方法,成员变量,分类,属性等结构声明,也包含了objc_class的完整声明.当我们使用Xcode创建一个类的时候一般都是调用的这里.
/** Runtime对外提供的接口,包含方法,成员变量,分类,属性等结构声明,也包含了objc_class的完整声明 **/ /* Types */ #if !OBJC_TYPES_DEFINED /// 表示一个类中的方法 /// An opaque type that represents a method in a class definition. typedef struct objc_method *Method; /// 表示类中的一个成员变量 /// An opaque type that represents an instance variable. typedef struct objc_ivar *Ivar; /// 表示一个分类 /// An opaque type that represents a category. typedef struct objc_category *Category; /// 表示一个属性 /// An opaque type that represents an Objective-C declared property. typedef struct objc_property *objc_property_t; /// 类的声明结构 struct objc_class { Class _Nonnull isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__ Class _Nullable super_class OBJC2_UNAVAILABLE; const char * _Nonnull name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; #endif } OBJC2_UNAVAILABLE; /* Use `Class` instead of `struct objc_class *` */
可以看到objc_class的结构声明中有isa指针,这个指针是Class类型,然后我们顺藤摸瓜,继续查找Class的定义来源.然后找到了objc-private.h文件,进入文件后我们看到结构体objc_class和objc_object的不完整声明如下:
// MARK: - objc_class 和 objc_object 不完整声明 struct objc_class; struct objc_object;
接着是用typedef 将这两个类型取了两个熟悉的名字:Class指针和id指针:
// MARK: - 将objc_class类型取名为Class指针类型;将objc_object类型取名为id指针类型 typedef struct objc_class *Class; typedef struct objc_object *id;
往下就是isa的声明union(联合体),isa_t中有两个初始化函数,两个成员变量,cls和bits,还有一个结构体成员.其中在不同的os平台,有不同的声明.
# if __arm64__ # define ISA_MASK 0x0000000ffffffff8ULL # define ISA_MAGIC_MASK 0x000003f000000001ULL # define ISA_MAGIC_VALUE 0x000001a000000001ULL # define ISA_BITFIELD \ uintptr_t nonpointer : 1; \ uintptr_t has_assoc : 1; \ uintptr_t has_cxx_dtor : 1; \ uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \ uintptr_t magic : 6; \ uintptr_t weakly_referenced : 1; \ uintptr_t deallocating : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 19 # define RC_ONE (1ULL<<45) # define RC_HALF (1ULL<<18) # elif __x86_64__ # define ISA_MASK 0x00007ffffffffff8ULL # define ISA_MAGIC_MASK 0x001f800000000001ULL # define ISA_MAGIC_VALUE 0x001d800000000001ULL # define ISA_BITFIELD \ uintptr_t nonpointer : 1; \ uintptr_t has_assoc : 1; \ uintptr_t has_cxx_dtor : 1; \ uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \ uintptr_t magic : 6; \ uintptr_t weakly_referenced : 1; \ uintptr_t deallocating : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 8 # define RC_ONE (1ULL<<56) # define RC_HALF (1ULL<= 2 || (__arm64__ && !__LP64__) // armv7k or arm64_32 # define ISA_INDEX_IS_NPI_BIT 0 # define ISA_INDEX_IS_NPI_MASK 0x00000001 # define ISA_INDEX_MASK 0x0001FFFC # define ISA_INDEX_SHIFT 2 # define ISA_INDEX_BITS 15 # define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS) # define ISA_INDEX_MAGIC_MASK 0x001E0001 # define ISA_INDEX_MAGIC_VALUE 0x001C0001 # define ISA_BITFIELD \ uintptr_t nonpointer : 1; \ uintptr_t has_assoc : 1; \ uintptr_t indexcls : 15; \ uintptr_t magic : 4; \ uintptr_t has_cxx_dtor : 1; \ uintptr_t weakly_referenced : 1; \ uintptr_t deallocating : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 7 # define RC_ONE (1ULL<<25) # define RC_HALF (1ULL<<6)
nonpointer: 标记此isa是否是tagged pointer优化后的isa.占用1bit.值为1说明是优化后的isa.具体参考 链接 ,tagged pointer是对实例对象的优化,默认是true,并且是isClass的判断,这是我看源码的理解,不对请指正
has_assoc:标记object是否有关联对象,没有,释放更快
has_cxx_dtor:标记是否有西沟函数,没有,释放更快
shiftcls:类对象(Class,meta-Class对象)内存地址信息
magic:标记object是否初始化完成
weakly_refrenced:标记object是否有weak指针指向它
deallocating:标记object是否正在释放
has_sidetable_rc:标记object的extra_rc位数能否存的下object的引用计数,存不下即has_sidetable_rc=1,存在全局的SideTable里面
extra_rc:存储object的引用计数,存不下,存在全局的SideTable里面
下面是object的完整声明:
// MARK: - object的完整声明 struct objc_object { private: // 私有成员变量: isa指针 isa_t isa; // 公有函数 public: // 通过这个函数获取不支持tagged pointer的类指针 // ISA() assumes this is NOT a tagged pointer object Class ISA(); // 通过这个函数获取支持tagged pointer的类指针 // getIsa() allows this to be a tagged pointer object Class getIsa(); // 以下几个函数是isa的初始化函数 // initIsa()用来初始化一个新的对象的isa // initIsa() should be used to init the isa of new objects only. // changeIsa 修改一个对象的isa // If this object already has an isa, use changeIsa() for correctness. // initInstanceIsa()用来初始化一个实例对象的isa // initInstanceIsa(): objects with no custom RR/AWZ // initClassIsa()用来初始化一个类对象的isa // initClassIsa(): class objects // initProtocolIsa()用来初始化一个protocol的isa // initProtocolIsa(): protocol objects // initIsa()还用来初始化其它类型对象的isa // initIsa(): other objects void initIsa(Class cls /*nonpointer=false*/); void initClassIsa(Class cls /*nonpointer=maybe*/); void initProtocolIsa(Class cls /*nonpointer=maybe*/); void initInstanceIsa(Class cls, bool hasCxxDtor); // changeIsa() should be used to change the isa of existing objects. // If this is a new object, use initIsa() for performance. Class changeIsa(Class newCls); // tagged pointer 相关 bool hasNonpointerIsa(); bool isTaggedPointer(); bool isBasicTaggedPointer(); bool isExtTaggedPointer(); // 是否是Class bool isClass(); // 关联对象相关 // object may have associated objects? bool hasAssociatedObjects(); void setHasAssociatedObjects(); // weak指针相关 // object may be weakly referenced? bool isWeaklyReferenced(); void setWeaklyReferenced_nolock(); // 对象是否有析构函数 // object may have -.cxx_destruct implementation? bool hasCxxDtor(); // retain 和 release 操作对象的引用计数 声明函数 // Optimized calls to retain/release methods id retain(); void release(); id autorelease(); // retain 和 release 操作对象的引用计数 实现函数 // Implementations of retain/release methods id rootRetain(); bool rootRelease(); id rootAutorelease(); bool rootTryRetain(); bool rootReleaseShouldDealloc(); uintptr_t rootRetainCount(); // 释放销毁对象相关 // Implementation of dealloc methods bool rootIsDeallocating(); void clearDeallocating(); void rootDealloc(); // 私有函数 上面一些公有函数的调用函数 private: void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor); // Slow paths for inline control id rootAutorelease2(); bool overrelease_error(); #if SUPPORT_NONPOINTER_ISA // Unified retain count manipulation for nonpointer isa id rootRetain(bool tryRetain, bool handleOverflow); bool rootRelease(bool performDealloc, bool handleUnderflow); id rootRetain_overflow(bool tryRetain); bool rootRelease_underflow(bool performDealloc); void clearDeallocating_slow(); // Side table retain count overflow for nonpointer isa void sidetable_lock(); void sidetable_unlock(); void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced); bool sidetable_addExtraRC_nolock(size_t delta_rc); size_t sidetable_subExtraRC_nolock(size_t delta_rc); size_t sidetable_getExtraRC_nolock(); #endif // Side-table-only retain count bool sidetable_isDeallocating(); void sidetable_clearDeallocating(); bool sidetable_isWeaklyReferenced(); void sidetable_setWeaklyReferenced_nolock(); id sidetable_retain(); id sidetable_retain_slow(SideTable& table); uintptr_t sidetable_release(bool performDealloc = true); uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true); bool sidetable_tryRetain(); uintptr_t sidetable_retainCount(); #if DEBUG bool sidetable_present(); #endif };
以上就是objc_object的具体声明结构,里面有许多值得深究的问题,也是接下来会继续关注的问题.
二.实例对象的初始化
1.alloc
下面我们来看一个对象的实例化过程:
Class newClass = objc_allocateClassPair(objc_getClass("NSObject"), "newClass", 0); objc_registerClassPair(newClass); id newObject = [[newClass alloc]init]; NSLog(@"%s",class_getName([newObject class])); NSLog(@"Hello, World!");
上面代码时创建一个newClass类,并且用这个新类实例化一个newObject对象.查看一下alloc方法和init方法的调用栈,其中省略了中间过程:
id _objc_rootAlloc(Class cls) └── static id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) └── id class_createInstance(Class cls, size_t extraBytes) └── id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, bool cxxConstruct, size_t *outAllocatedSize) ├── size_t instanceSize(size_t extraBytes) ├── void *calloc(size_t, size_t) └── inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
其中NSObject.mm中对alloc的实现如下:
+ (id)alloc { return _objc_rootAlloc(self); }
这里面调用了一个私有函数,返回一个id类型(objc_object)如下:
id _objc_rootAlloc(Class cls) { return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/); }
NSObject.mm对callAlloc()实现:
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate // shortcutting optimizations. static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) { if (slowpath(checkNil && !cls)) return nil; #if __OBJC2__ if (fastpath(!cls->ISA()->hasCustomAWZ())) { // No alloc/allocWithZone implementation. Go straight to the allocator. // fixme store hasCustomAWZ in the non-meta class and // add it to canAllocFast's summary if (fastpath(cls->canAllocFast())) { // No ctors, raw isa, etc. Go straight to the metal. bool dtor = cls->hasCxxDtor(); id obj = (id)calloc(1, cls->bits.fastInstanceSize()); if (slowpath(!obj)) return callBadAllocHandler(cls); obj->initInstanceIsa(cls, dtor); return obj; } else { // Has ctor or raw isa or something. Use the slower path. id obj = class_createInstance(cls, 0); if (slowpath(!obj)) return callBadAllocHandler(cls); return obj; } } #endif // No shortcuts available. if (allocWithZone) return [cls allocWithZone:nil]; return [cls alloc]; }
其中有个class_createInstance()函数,这函数中会调用_class_createInstanceFromZone()函数:
static __attribute__((always_inline))
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
bool cxxConstruct = true,
size_t *outAllocatedSize
static __attribute__((always_inline)) id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, bool cxxConstruct = true, size_t *outAllocatedSize = nil) { if (!cls) return nil; assert(cls->isRealized()); // Read class's info bits all at once for performance bool hasCxxCtor = cls->hasCxxCtor(); bool hasCxxDtor = cls->hasCxxDtor(); bool fast = cls->canAllocNonpointer(); size_t size = cls->instanceSize(extraBytes); if (outAllocatedSize) *outAllocatedSize = size; id obj; if (!zone && fast) { obj = (id)calloc(1, size); if (!obj) return nil; obj->initInstanceIsa(cls, hasCxxDtor); } else { if (zone) { obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size); } else { obj = (id)calloc(1, size); } if (!obj) return nil; // Use raw pointer isa on the assumption that they might be // doing something weird with the zone or RR. obj->initIsa(cls); } if (cxxConstruct && hasCxxCtor) { obj = _objc_constructOrFree(obj, cls); } return obj; }
这里面有:1)instanceSize()是给对象分配内存空间:
size_t instanceSize(size_t extraBytes) { size_t size = alignedInstanceSize() + extraBytes; if (size < 16) size = 16; return size; } uint32_t alignedInstanceSize() { return word_align(unalignedInstanceSize()); } uint32_t unalignedInstanceSize() { assert(isRealized()); return data()->ro->instanceSize; }
2)initIsa()初始化isa指针
inline void objc_object::initIsa(Class cls) { initIsa(cls, false, false); } inline void objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) { assert(!isTaggedPointer()); // 不是tagged pointer if (!nonpointer) { isa.cls = cls; } else { assert(!DisableNonpointerIsa); assert(!cls->instancesRequireRawIsa()); isa_t newisa(0); #if SUPPORT_INDEXED_ISA assert(cls->classArrayIndex() > 0); newisa.bits = ISA_INDEX_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE newisa.has_cxx_dtor = hasCxxDtor; newisa.indexcls = (uintptr_t)cls->classArrayIndex(); #else newisa.bits = ISA_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE newisa.has_cxx_dtor = hasCxxDtor; newisa.shiftcls = (uintptr_t)cls >> 3; #endif // This write must be performed in a single store in some cases // (for example when realizing a class because other threads // may simultaneously try to use the class). // fixme use atomics here to guarantee single-store and to // guarantee memory order w.r.t. the class index table // ...but not too atomic because we don't want to hurt instantiation isa = newisa; } }
2.init
init()函数调用栈很简单,只是调用了_objc_rootInit()私有函数,并返回对象本身
- (id)init { return _objc_rootInit(self); } id _objc_rootInit(id obj) { // In practice, it will be hard to rely on this function. // Many classes do not properly chain -init calls. return obj; }
对象的初始化过程可以总结为分配内存空间并且初始化isa_t结构的过程.
参考文献:
https://blog.devtang.com/2014/05/30/understand-tagged-pointer/
作者:偶尔登南山
链接:https://www.jianshu.com/p/da68505cc383
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Phoenix解读 | Phoenix源码解读之索引
- Phoenix解读 | Phoenix源码解读之SQL
- Flink解读 | 解读Flink的声明式资源管理与自动扩缩容设计
- 解读阿里巴巴 Java 代码规范,第 2 部分: 从代码处理等方面解读阿里巴巴 Java 代码规范
- websocket 协议解读
- AQS源码详细解读
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。