C/C++/OC 內(nèi)存布局

這幾天看了些關(guān)于內(nèi)存布局的文章,發(fā)帖總結(jié)摘錄下重點(diǎn)。

C語(yǔ)言的內(nèi)存模型
C語(yǔ)言的內(nèi)存模型

程序代碼區(qū)(code area)

存放函數(shù)體的二進(jìn)制代碼

靜態(tài)數(shù)據(jù)區(qū)(data area)

也稱全局?jǐn)?shù)據(jù)區(qū),包含的數(shù)據(jù)類型比較多,如全局變量、靜態(tài)變量、一般常量、字符串常量。其中:

  • 全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。
  • 常量數(shù)據(jù)(一般常量、字符串常量)存放在另一個(gè)區(qū)域。

注意:靜態(tài)數(shù)據(jù)區(qū)的內(nèi)存在程序結(jié)束后由操作系統(tǒng)釋放。

堆區(qū)(heap area)

一般由程序員分配和釋放,若程序員不釋放,程序運(yùn)行結(jié)束時(shí)由操作系統(tǒng)回收。malloc()、calloc()、free()等函數(shù)操作的就是這塊內(nèi)存。

注意:這里所說(shuō)的堆區(qū)與數(shù)據(jù)結(jié)構(gòu)中的堆不是一個(gè)概念,堆區(qū)的分配方式倒是類似于鏈表。

棧區(qū)(stack area)

由系統(tǒng)自動(dòng)分配釋放,存放函數(shù)的參數(shù)值、局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

命令行參數(shù)區(qū)

存放命令行參數(shù)和環(huán)境變量的值,如通過(guò)main()函數(shù)傳遞的值。

C語(yǔ)句的個(gè)部分會(huì)出現(xiàn)在哪些段中
可執(zhí)行文件的段在內(nèi)存中如何布局

C語(yǔ)言的內(nèi)存布局相對(duì)簡(jiǎn)單,但也是最基本的。在編譯過(guò)程中就已經(jīng)確定了所有函數(shù)的地址(偏移地址)。

C語(yǔ)言沒(méi)有對(duì)象的概念,那么變量的布局非常簡(jiǎn)單,固定。除去全局,靜態(tài)的變量分配在靜態(tài)數(shù)據(jù)區(qū),其它的臨時(shí)變量,參數(shù)等,要么分配在棧區(qū)由系統(tǒng)自動(dòng)管理,要么由malloc()、calloc()、free()等函數(shù)由程序員管理分配在堆區(qū)。而變量本身的空間大小,在分配時(shí)是相對(duì)簡(jiǎn)單并可以確定的。

C++對(duì)象的內(nèi)存布局

C++語(yǔ)言在C的基礎(chǔ)上添加了面向?qū)ο蟮母拍?,引入了封裝,繼承,多態(tài)。而一個(gè)對(duì)象的內(nèi)存布局就相對(duì)于C語(yǔ)言的結(jié)構(gòu)體等在內(nèi)存的布局要復(fù)雜的多。
在C++中,有兩種數(shù)據(jù)成員(class data members):static 和nonstatic,以及三種類成員函數(shù)(class member functions):static、nonstatic和virtual:

C++數(shù)據(jù)成員及成員函數(shù)類型

現(xiàn)在我們有一個(gè)類Base,它包含了上面這5中類型的數(shù)據(jù)或函數(shù):

class Base
{
    public:
    
    Base(int i) :baseI(i){};
    
    int getI(){ return baseI; }
    
    static void countI(){};
    
    virtual void print(void){ cout << "Base::print()"; }
    
    virtual ~Base(){}
    
    private:
    
    int baseI;
    
    static int baseS;
};
Base類圖
Base內(nèi)存布局

可以看到,對(duì)一個(gè)C++對(duì)象來(lái)說(shuō),它的內(nèi)存布局僅有虛表指針和非靜態(tài)成員,而其他的靜態(tài)成員,成員函數(shù)(靜態(tài),非靜態(tài)),虛表等都是布局在類上的。
當(dāng)然,這是沒(méi)有考慮繼承的情況。繼承情況下會(huì)更復(fù)雜一些。可以參考(http://www.cnblogs.com/QG-whz/p/4909359.html

OC對(duì)象的內(nèi)存布局

OC對(duì)象的內(nèi)存布局相對(duì)于C++更為復(fù)雜一些,出現(xiàn)了元類的概念:


OC對(duì)象內(nèi)存布局

簡(jiǎn)單來(lái)說(shuō),最左邊的是對(duì)象(Instance),中間的是類(Class),最右邊的是元類(Meta Class)。屬性(包括父類)都保存在對(duì)象本身的存儲(chǔ)空間內(nèi);本類的實(shí)例方法保存在類中,本類的類方法保存在元類中。

那么對(duì)象的內(nèi)存布局如下:isa 指針指向其類,其余空間保存各級(jí)的屬性(ivar)

Paste_Image.png

而類的內(nèi)存布局如下:

struct objc_class
{
    struct objc_class* isa;
    struct objc_class* super_class;
    const char* name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list* ivars;
    struct objc_method_list** methodLists;
    struct objc_cache* cache;
    struct objc_protocol_list* protocols;
};

isa 指針指向其元類,super_class指針指向其父類,此外還包含實(shí)例變量列表、方法列表、協(xié)議列表。
這里特別要指出的是實(shí)例變量列表中的實(shí)例變量的定義如下,它包含了變量的名稱、類型、偏移等,但卻不包括變量的值-----值在對(duì)象而非類中:

struct objc_ivar {
    char *ivar_name  OBJC2_UNAVAILABLE;
    char *ivar_type  OBJC2_UNAVAILABLE;
    int ivar_offset  OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space        OBJC2_UNAVAILABLE;
#endif
}

參考文章:
C語(yǔ)言的代碼內(nèi)存布局詳解
C語(yǔ)言內(nèi)存模型
圖說(shuō)C++對(duì)象模型:對(duì)象內(nèi)存布局詳解
c++的類的內(nèi)存布局
OC優(yōu)缺點(diǎn)
OC對(duì)象的內(nèi)存布局
Objetive-C內(nèi)存布局

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容