隻是小小記錄一下,内容不完整
- OC底層實作是c\c++,oc的面向對象都是基于c\c++實作
- NSObject c++ 底層結構
struct NSObject_IMPL {
//CLass 指針,64位占8個位元組
__unsafe_unretained Class isa;
};
//Class
typedef struct objc_class *Class
oc中的定義
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
//
typedef struct objc_class *Class;
- 一個NSObject對象占用多少記憶體?
-
系統配置設定了16個位元組給nsobject對象(通過malloc_size函數獲得)
通過檢視alloc源碼,可以看到為NSObject對象配置設定記憶體時,硬性規定至少為16位元組
-
但NSObject對象實際隻使用8個位元組(64位環境下,通過class_getInstanceSize獲得,其實際調用的函數如下,從注釋中可知這是成員變量的大小,傳回的是記憶體對齊後的大小)
傳回記憶體對齊
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>
@interface Student : NSObject
@property (nonatomic, assign) char num;
@property (nonatomic, assign) int age;
@end
@implementation Student
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// // insert code here...
Student *stu = [[Student alloc] init];
stu.age = 10;
stu.num = 'a';
//class_getInstanceSize傳回的是類的對象的成員變量所占記憶體大小(對齊過的)
NSLog(@"%lu", class_getInstanceSize([Student class]));
//傳回stu指針所指向的記憶體大小
NSLog(@"%lu", malloc_size((__bridge const void *)stu));
}
return 0;
}
//列印結果
//2021-07-21 16:19:36.975209+0800 對象的本質[27424:2825069] 16
//2021-07-21 16:19:36.977476+0800 對象的本質[27424:2825069] 16
//轉為c++, Student本質
struct Student_IMPL {
struct NSObject_IMPL NSObject_IVARS; //隻有isa, 8個位元組
char _num; //1
int _age; //4
};
//NSOject本質
struct NSObject_IMPL {
__unsafe_unretained Class isa;
};
分别存儲着num,age(16進制, iOS是小端模式,記憶體讀取要反着讀)
!!!記憶體對齊 結構體嵌套 學習!!!!!
- 結構體記憶體對齊原則:
- 第一個成員從偏移量為0開始存儲,其餘成員從位址為自身大小的整數倍開始存儲。
- 成員為結構體時,該結構體從位址為其最大成員的整數倍開始存儲
- 結構體的總大小,即sizeof()出來的結果是其最大成員大小的整數倍。
- 補充
- 擷取記憶體大小
-
sizeof:操作符:
傳入資料類型,輸出記憶體大小。編譯時固定,隻與類型相關,與具體數值無關。(如:bool 2位元組,int 4位元組,對象(指針)8位元組)
- class_getInstanceSize: runtime的api,傳入對象,輸出對象實際所占的記憶體大小,本質是對象中成員變量的大小。與sizeof()傳回值相同。
-
malloc_size:
擷取系統實際配置設定的記憶體大小
有一個對齊的概念,與記憶體對齊概念不同,為oc對象配置設定的記憶體大小為16位元組倍數,空間換時間,以16位元組為一塊,這就保證了CPU在讀取的時候,按照塊讀取就可以,效率更高,同時還不容易混亂。()
- oc對象的分類
-
instance對象,執行個體對象
在記憶體中存儲的資訊 有isa、成員變量的具體值
-
class對象,類對象
類對象在記憶體隻有一份
類對象存儲的内容為
isa指針、superclass指針
類的屬性資訊、類的對象方法資訊
類的協定資訊、類的成員變量資訊
…
-
meta-class對象,元類對象
object_getClass擷取元類對象,參數為類對象
注意:class方法傳回的對象一定是類對象,不是元類對象
每個類隻有一個元類對象
元類對象存儲的内容:
isa、superclass指針
類方法
…
-
objc_getClass(<const char * _Nonnull name>)
參數為字元串類名,傳回相應的類對象
object_getClass(id _Nullable obj)
參數為執行個體對象,傳回類對象
參數為類對象,傳回元類對象
參數為元類對象,傳回NSObject(基類)
-
isa指針
執行個體對象isa指向類對象
類對象isa指向元類對象
元類對象isa指向基類的元類對象
實際上,在64bit開始,isa需要進行一次位運算即 isa & ISA_MASK,才能計算出指向的類或元類對象的真實位址
對于ISA_MASK的定義
- struct objc_class的結構
//objc-runtime-new.h中
//繼承的objc_object下面有複制部分 裡面的成員隻有isa
//
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // 方法緩存 formerly cache pointer and vtable
class_data_bits_t bits; // 用于擷取具體的類資訊 class_rw_t * plus custom rr/alloc flags
...
}
struct objc_object {
private:
isa_t isa;
public:
...
//一些方法
}
struct objc_class的結構可以簡化為
struct objc_class {
// Class ISA;
Class superclass;
cache_t cache; // 方法緩存 formerly cache pointer and vtable
class_data_bits_t bits; // 用于擷取具體的類資訊 class_rw_t * plus custom rr/alloc flags
}
-
對class_rw_t的了解
rw代表可讀可寫
類中的屬性、方法、協定等資訊都儲存在class_rw_t中
-
對class_ro_t的了解
ro代表隻讀
存儲了目前類在編譯期就确定了的屬性、方法、協定
OC對象中存儲的屬性、方法、遵循的協定資料其實被存儲在這兩塊兒記憶體區域的,而我們通過runtime動态修改類的方法時,是修改在class_rw_t區域中存儲的方法清單