Runtime原始碼 類 物件 isa

2021-09-11 12:22:28 字數 3733 閱讀 2335

oc做為一門動態語言,runtime是其最大的特點,它是一套底層的 c 語言 api,是 ios 系統的核心之一。開發者在編碼過程中,可以給任意乙個物件傳送訊息,在編譯階段只是確定了要向接收者傳送這條訊息,而接受者將要如何響應和處理這條訊息,那就要看執行時來決定了。在日常開發過程中類、物件、屬性算是最常見的了,今天以物件為切入點,分析一下物件和類在runtime層面的表示。

類在runtime的表示為:

struct objc_object 

複製**

union isa_t 

isa_t(uintptr_t value) : bits(value)

class cls;

}複製**

可以看到這個聯合體裡面有個class型別的屬性cls,看起來裡面應該是關於這個物件的類的相關資訊,那我們再看看class包含了哪些內容。

struct objc_class : objc_object 

複製**

由此可見class是乙個objcclass型別的結構體,而objc_class繼承自objc_object,說明類也是乙個物件,只是比普通的物件多了一些屬性,比如superclass等。

先不看這些屬性,這裡還有乙個很奇怪的問題,既然類也是乙個objc_object,那就是說類也有乙個isa指標,那類的isa指標指向**呢?檢視了不少資料,這篇講的挺好:classes and metaclasses

大致意思是在class之上還有叫做元類(meta class)的存在,而class的isa指標就是指向對應的meta class。

我們都知道class中儲存的是描述物件的相關資訊,那麼相應的meta class中存放的就是描述class相關資訊。說的更直白一點,在我們寫**時,通過物件來呼叫的方法(例項方法)都是儲存在class中的,通過類名來呼叫的方法(類方法)都是儲存在meta class中的。

到這裡物件和類的關係已經比較清楚了,但是如果細細思考一下,會發現還有乙個問題,就是meta class也是有isa指標的,那麼這個isa又指向了**呢?在上面給出的那篇文章裡面有這麼一張圖:

由圖可知:meta class的isa指向root meta class(絕大部分情況下是nsobject),root meta class的isa指標指向自己。

先看看完整的isa_t,因為執行環境是osx,所以只擷取x86_64部分,arm64的區別只在於部分欄位的位數不同,欄位是完全相同的:

union isa_t 

isa_t(uintptr_t value) : bits(value)

class cls;

uintptr_t bits;

# __x86_64__

# define isa_mask 0x00007ffffffffff8ull

# define isa_magic_mask 0x001f800000000001ull

# define isa_magic_value 0x001d800000000001ull

struct ;

}複製**

看這個定義只能大概看出個框架,下面從isa的初始化過程來看看isa_t究竟是如何儲存類或者元類的相關資訊。

inline void 

objc_object::initinstanceisa(class cls, bool hascxxdtor)

inline void

objc_object::initisa(class cls, bool nonpointer, bool hascxxdtor)

else

}複製**

上來就看不懂,nonpointer是個什麼,為什麼在這裡傳的是true?在之前那位大神的另一篇文章中也有解釋:non-pointer isa。

大概的意思是在64位系統中,為了降低記憶體使用,提公升效能,isa中有一部分字段用來儲存其他資訊。這也解釋了上面isa_t的那部分結構體。

這有點像taggedpointer,兩者之間有什麼區別?備註一下後面再研究。

現在知道了nonpointer為什麼是true,那麼把initisa方法先簡化一下:

inline void 

objc_object::initisa(class cls, bool nonpointer, bool hascxxdtor)

# define isa_magic_value 0x001d800000000001ull

複製**

一共三部分:

newisa.bits = isa_magic_value;

從isa_magic_value的定義中可以看到這個字段初始化了兩個部分,乙個是magic欄位(6位:111011),乙個是nonpointer欄位(1位:1),magic欄位用於校驗,nonpointer之前已經詳細分析過了。

newisa.has_cxx_dtor = hascxxdtor; 這個字段儲存類是否有c++析構器。

newisa.shiftcls = (uintptr_t)cls >> 3; 將cls右移3位存到shiftcls中,從isa_t的結構體中也可以看到低3位都是用來儲存其他資訊的,既然可以右移三位,那就代表類位址的低三位全部都是0,否則就出錯了,補0的作用應該是為了位元組對齊。

inline class 

objc_object::isa

() # define isa_mask 0x00007ffffffffff8ull

複製**

其實就是取isa_t結構體的shiftcls欄位。

// 是否曾經或正在被關聯引用,如果沒有,可以快速釋放記憶體 uintptr_t has_assoc : 1;

// 物件是否曾經或正在被弱引用,如果沒有,可以快速釋放記憶體 uintptr_t weakly_referenced : 1;

// 物件是否正在釋放記憶體 uintptr_t deallocating : 1;

// 物件的引用計數太大,無法儲存 uintptr_t has_sidetable_rc : 1;

// 物件的引用計數超過1,比如10,則此值為9 uintptr_t extra_rc : 8;

通過注釋(class_rw_t * plus custom rr/alloc flags)可以看到:class_data_bits_t其實是class_rw_t* 加上自定義的rr/alloc標誌,rr/alloc標誌是指含有的retain/release/autorelease/retaincount/alloc等。

struct class_rw_t 

複製**

裡面有個很相似的結構體class_ro_t,其定義如下:

struct class_ro_t 

};複製**

rw是指readwrite,ro是指readonly。也就是說在可讀可寫的結構體中存放了乙個唯讀的結構體,而且這兩個結構體很相似。

資料:物件、類和isa

isa和class

objc 編譯Runtime 原始碼

而這篇文章的目的,就是教你從蘋果提供的runtime原始碼,編譯出自己的libobjc.a.dylib。進而你可以除錯它,深入了解它。1 libc 庫libc是linux下的ansi c的函式庫。2 xnu是核心,就像linux一樣,當然,xnu是由mach freebs d核心以及蘋果自己的驅動框...

Spring cloud 原始碼類

eurekaserverinitializerconfiguration 註解加入configuration spring 便可以載入改類,該類 有乙個執行緒啟動方法 override public void start catch exception ex start 就會將spring clou...

CCTextureCache類原始碼分析 2

cctexturecache類原始碼分析 2 在cctexturecache類原始碼分析 1 中,我們分析了cctexturecache如何實現 紋理快取的,但是在分析的過程中,我們忽略了很多東西,比如ccimage類 原始碼分析 1 ccimage繼承自ccobject 2 成員變數,這些變數需要...