在上一篇文章中咱們說到過isa實際上是個聯合體,那麼到底什麼是聯合體,做者再帶你們溫習一下:ios
聯合體
在進行某些算法的C語言編程的時候,須要使幾種不一樣類型的變量存放到同一段內存單元中。也就是使用覆蓋技術,幾個變量互相覆蓋。這種幾個不一樣的變量共同佔用一段內存的結構,在C語言中,被稱做「共用體」類型結構,簡稱共用體,也叫聯合體。算法
聯合體和結構體
「聯合」與「結構」有一些類似之處。但二者有本質上的不一樣。在結構中各成員有各自的內存空間,一個結構體變量的總長度大於等於各成員長度之和。而在「聯合」中,各成員共享一段內存空間,一個聯合變量的長度等於各成員中最長的長度。應該說明的是,這裏所謂的共享不是指把多個成員同時裝入一個聯合變量內,而是指該聯合變量可被賦予任一成員值,但每次只能賦一種值,賦入新值則衝去舊值。以下面介紹的「單位」變量,如定義爲一個可裝入「班級」或「教研室」的聯合後,就容許賦予整型值(班級)或字符型(教研室)。要麼賦予整型值,要麼賦予字符型,不能把二者同時賦予它。聯合類型的定義和聯合變量的說明:一個聯合類型必須通過定義以後,才能把變量說明爲該聯合類型。編程
演示代碼以下:bash
#include<iostream>
using namespace std;
union U1
{
int n;
char s[11];
double d;
};
union U2
{
int n;
char s[5];
double d;
};
int main()
{
U1 u1;
U2 u2;
cout<<sizeof(u1)<<'\t'<<sizeof(u2)<<endl;
cout<<"u1各數據地址:\n"<<&u1<<'\t'<<&u1.d<<'\t'<<&u1.s<<'\t'<<&u1.n<<endl;
cout<<"u1各數據地址:\n"<<&u2<<'\t'<<&u2.d<<'\t'<<&u2.s<<'\t'<<&u2.n<<endl;
}
複製代碼
上述代碼中:
對於U1聯合體,s佔11字節,n佔4字節,d佔8字節,所以其至少需1字節的空間。然而其實際大小並非11,用運算符sizeof測試其大小爲16。這是由於這裏存在字節對齊的問題,11既不能被4整除,也不能被8整除。所以補充字節到16,這樣就符合全部成員的自身對齊了。從這裏能夠看出聯合體所佔的空間不只取決於最寬成員,還跟全部成員有關係,即其大小必須知足兩個條件:數據結構
對於U2聯合體,同理知道,用運算符sizeof測試其大小爲8。ide
運行後的結果以下:函數
16 8
u1各數據地址:
0x7ffeefbff608 0x7ffeefbff608 0x7ffeefbff608 0x7ffeefbff608
u1各數據地址:
0x7ffeefbff5d0 0x7ffeefbff5d0 0x7ffeefbff5d0 0x7ffeefbff5d0
Program ended with exit code: 0
複製代碼
上篇文章中,咱們比對兩個類是否相等最終判斷了測試
isa.bits & ISA_MASK
複製代碼
的值是否相等。那爲何判斷這兩個的值是否相等便可呢,這便是本文討論的話題。
首先瀏覽一下isa源碼:優化
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if SUPPORT_PACKED_ISA
// extra_rc must be the MSB-most field (so it matches carry/overflow flags)
// nonpointer must be the LSB (fixme or get rid of it)
// shiftcls must occupy the same bits that a real class pointer would
// bits + RC_ONE is equivalent to extra_rc + 1
// RC_HALF is the high bit of extra_rc (i.e. half of its range)
// future expansion:
// uintptr_t fast_rr : 1; // no r/r overrides
// uintptr_t lock : 2; // lock for atomic property, @synch
// uintptr_t extraBytes : 1; // allocated with extra bytes
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct {
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
struct {
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<<7)
};
# else
# error unknown architecture for packed isa
# endif
// SUPPORT_PACKED_ISA
#endif
#if SUPPORT_INDEXED_ISA
# if __ARM_ARCH_7K__ >= 2
# define ISA_INDEX_IS_NPI 1
# 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
struct {
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)
};
# else
# error unknown architecture for indexed isa
# endif
// SUPPORT_INDEXED_ISA
#endif
};
複製代碼
去掉註釋,以及其餘平臺的兼容性代碼(主要是x86_64相關的代碼)後簡化以下:ui
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct {
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)
};
};
複製代碼
初步看到isa_t
的時候,相信你們仍是比較難以理解:
# define ISA_MASK 0x0000000ffffffff8ULL
定義的數字的含義1.冒號是位域
位域
位域是指信息在存儲時,並不須要佔用一個完整的字節, 而只需佔幾個或一個二進制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位便可。爲了節省存儲空間,並使處理簡便,C語言又提供了一種數據結構,稱爲「位域」或「位段」。所謂「位域」是把一個字節中的二進位劃分爲幾 個不一樣的區域, 並說明每一個區域的位數。每一個域有一個域名,容許在程序中按域名進行操做。 這樣就能夠把幾個不一樣的對象用一個字節的二進制位域來表示。
首先你們須要知道,無論X86仍是arm的處理器都是64位的。16位操做系統中,int 佔16位;在32位操做系統中,int 佔32位。可是後來人們已經習慣了 int 佔32位,所以在64位操做系統中,int 仍爲32位。64位整型用 long long 或者64位即8個字節,即64位。
在文章結構體對齊(圖解)與位域 中你們能夠了解到位域對於結構體的大小起到必定的做用。
所以咱們不難理解:isa_t中的bits佔用了64位的數據。
上一篇文章中的
isa.bits & ISA_MASK
複製代碼
中
# define ISA_MASK 0x0000000ffffffff8ULL
複製代碼
咱們來看一下,這個0x0000000ffffffff8ULL
換算成二進制
有31位都是1。 對isa.bits
和ISA_MASK
進行與操做,會發生什麼「化學反應」呢?
位操做符
位操做符包括:&(按位與)、|(按位或)、^(按位異或)。這三個操做符很是簡單,須要注意的是,這三個操做符操做的必須是整數。
這裏以&爲例:
當&兩邊是bool類型的值時,該運算符做爲邏輯運算符。做用以下:
當運算符兩邊的表達式的結果都爲true時,整個運算結果才爲true,不然,只要有一方爲false,則結果爲false。
當&兩邊不是bool類型的時候,該運算符做爲位運算符,將兩邊的值做爲二進制展開,依次對每一位進行 按位與。做用以下:
11100101 & 01011010 = 01000000
複製代碼
通過以上分析,咱們不可貴出:
上圖中能夠看出ISA_MASK的值轉化爲二進制中有33位都爲1,上面的例子能夠看出,按位與的做用是能夠取出這33位中的值。那麼此時很明顯了,同ISA_MASK進行按位與運算便可以取出Class的值。
寫到這裏,咱們再回頭看看isa_t的源碼,不難發現,這33位對應的是結構體的shiftcls
的位域。其餘的位域在最後也一併作個預習吧:
struct {
// 1表明優化後的使用位域存儲更多的信息。
uintptr_t nonpointer : 1;
// 是否有設置過關聯對象
uintptr_t has_assoc : 1;
// 是否有C++析構函數
uintptr_t has_cxx_dtor : 1;
// 存儲着Class對象的內存地址信息
uintptr_t shiftcls : 33;
// 用於在調試時分辨對象是否未完成初始化
uintptr_t magic : 6;
// 是否有被弱引用指向過。
uintptr_t weakly_referenced : 1;
// 對象是否正在釋放
uintptr_t deallocating : 1;
// 引用計數器是否過大沒法存儲在isa中
// 若是爲1,那麼引用計數會存儲在一個叫SideTable的類的屬性中
uintptr_t has_sidetable_rc : 1;
// 裏面存儲的值是引用計數器減1
uintptr_t extra_rc : 19;
};
複製代碼
isa
的部分字段的含義。但願你們對isa有更深的理解。
做者:kyson