objc_object解读
栏目: Objective-C · 发布时间: 7年前
内容简介: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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Parsing Techniques
Dick Grune、Ceriel J.H. Jacobs / Springer / 2010-2-12 / USD 109.00
This second edition of Grune and Jacobs' brilliant work presents new developments and discoveries that have been made in the field. Parsing, also referred to as syntax analysis, has been and continues......一起来看看 《Parsing Techniques》 这本书的介绍吧!