天天看點

iOS—對象的本質(學習筆記)

隻是小小記錄一下,内容不完整

  1. OC底層實作是c\c++,oc的面向對象都是基于c\c++實作
  2. 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;
           
  1. 一個NSObject對象占用多少記憶體?
  • 系統配置設定了16個位元組給nsobject對象(通過malloc_size函數獲得)

    通過檢視alloc源碼,可以看到為NSObject對象配置設定記憶體時,硬性規定至少為16位元組

    iOS—對象的本質(學習筆記)
  • 但NSObject對象實際隻使用8個位元組(64位環境下,通過class_getInstanceSize獲得,其實際調用的函數如下,從注釋中可知這是成員變量的大小,傳回的是記憶體對齊後的大小)

    傳回記憶體對齊

    iOS—對象的本質(學習筆記)
#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;
};

           
iOS—對象的本質(學習筆記)

分别存儲着num,age(16進制, iOS是小端模式,記憶體讀取要反着讀)

iOS—對象的本質(學習筆記)

!!!記憶體對齊 結構體嵌套 學習!!!!!

  1. 結構體記憶體對齊原則:
  • 第一個成員從偏移量為0開始存儲,其餘成員從位址為自身大小的整數倍開始存儲。
  • 成員為結構體時,該結構體從位址為其最大成員的整數倍開始存儲
  • 結構體的總大小,即sizeof()出來的結果是其最大成員大小的整數倍。
  1. 補充
  • 擷取記憶體大小
  • sizeof:操作符:

    傳入資料類型,輸出記憶體大小。編譯時固定,隻與類型相關,與具體數值無關。(如:bool 2位元組,int 4位元組,對象(指針)8位元組)

  • class_getInstanceSize: runtime的api,傳入對象,輸出對象實際所占的記憶體大小,本質是對象中成員變量的大小。與sizeof()傳回值相同。
  • malloc_size:

    擷取系統實際配置設定的記憶體大小

    有一個對齊的概念,與記憶體對齊概念不同,為oc對象配置設定的記憶體大小為16位元組倍數,空間換時間,以16位元組為一塊,這就保證了CPU在讀取的時候,按照塊讀取就可以,效率更高,同時還不容易混亂。()

  1. oc對象的分類
  • instance對象,執行個體對象

    在記憶體中存儲的資訊 有isa、成員變量的具體值

  • class對象,類對象

    類對象在記憶體隻有一份

iOS—對象的本質(學習筆記)
iOS—對象的本質(學習筆記)

類對象存儲的内容為

isa指針、superclass指針

類的屬性資訊、類的對象方法資訊

類的協定資訊、類的成員變量資訊

  • meta-class對象,元類對象

    object_getClass擷取元類對象,參數為類對象

    注意:class方法傳回的對象一定是類對象,不是元類對象

    每個類隻有一個元類對象

    iOS—對象的本質(學習筆記)
    iOS—對象的本質(學習筆記)

    元類對象存儲的内容:

    isa、superclass指針

    類方法

  1. objc_getClass(<const char * _Nonnull name>)

    參數為字元串類名,傳回相應的類對象

object_getClass(id _Nullable obj)

參數為執行個體對象,傳回類對象

參數為類對象,傳回元類對象

參數為元類對象,傳回NSObject(基類)

  1. isa指針

    執行個體對象isa指向類對象

    類對象isa指向元類對象

    元類對象isa指向基類的元類對象

    iOS—對象的本質(學習筆記)

實際上,在64bit開始,isa需要進行一次位運算即 isa & ISA_MASK,才能計算出指向的類或元類對象的真實位址

對于ISA_MASK的定義

iOS—對象的本質(學習筆記)
iOS—對象的本質(學習筆記)
iOS—對象的本質(學習筆記)
  • 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

}
           
iOS—對象的本質(學習筆記)
  • 對class_rw_t的了解

    rw代表可讀可寫

    類中的屬性、方法、協定等資訊都儲存在class_rw_t中

  • 對class_ro_t的了解

    ro代表隻讀

    存儲了目前類在編譯期就确定了的屬性、方法、協定

OC對象中存儲的屬性、方法、遵循的協定資料其實被存儲在這兩塊兒記憶體區域的,而我們通過runtime動态修改類的方法時,是修改在class_rw_t區域中存儲的方法清單