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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

区块链

区块链

长铗、韩锋 / 中信出版社 / 2016-7 / CNY 58.00

《区块链:从数字货币到信用社会》从历史与背景、发展现状、基础原理与技术、应用生态、存在的问题与挑战等方面论述了区块链是怎样立起来的,为什么人人都在谈论区块链,区块链的秘密在哪里、进阶区块链(第二代区块链技术)是什么,区块链怎么玩,怎样从信息互联网走向价值互联网,如何用法规约束和监管区块链,区块链走向何处、争议与挑战,并通过经济、金融、货币、法律、科技哲学等角度来加以分析区块链在各个方面遇到的问题和......一起来看看 《区块链》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码