剖析對象在內存中的存儲

對象在內存中的存儲

  • 棧、堆、BSS、數據段、代碼段是什麼?架構

    • 棧(stack):又稱做堆棧,用來存儲程序的局部變量(但不包括static聲明的變量,static修飾的數據存放於數據段中)。除此以外,在函數被調用時,棧用來傳遞參數和返回值。函數

    • 堆(heap):用於存儲程序運行中被動態分配的內存段,它的大小並不固定,可動態的擴張和縮減。操做函數(malloc/free)指針

    • BSS段(bss segment):一般用來存儲程序中未被初始化的全局變量和靜態變量的一塊內存區域。BSS是英文Block Started by Symbol的簡稱。BSS段輸入靜態內存分配code

    • 數據段(data segment):一般用來存儲程序中已被初始化的全局變量和靜態變量和字符串的一塊內存區域對象

    • 代碼段(code segment):一般是指用來存儲程序可執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經肯定,而且內存區域一般屬於只讀,某些架構也容許代碼段爲可寫,即容許修改程序。在代碼段中,也有可能包含一些只讀的常數變量,例如字符串常量。內存

內存

  • 搞清楚上面的概念再來研究下對象在內存中如何存儲?
Person *p1 = [Person new]

看這行代碼,先來看幾個注意點:字符串

  • new底層作的事情:it

    • 在堆內存中申請1塊合適大小的空間io

    • 在這塊內存上根據類模版建立對象。類模版中定義了什麼屬性就依次把這些屬性聲明在對象中;對象中還存在一個屬性叫作isa,是一個指針,指向對象所屬的類在代碼段中地址import

    • 初始化對象的屬性。這裏初始化有幾個原則:a、若是屬性的數據類型是基本數據類型則賦值爲0;b、若是屬性的數據類型是C語言的指針類型則賦值爲NULL;c、若是屬性的數據類型爲OC的指針類型則賦值爲nil。

    • 返回堆空間上對象的地址

  • 注意

    • 對象只有屬性,沒有方法。包括類自己的屬性和一個指向代碼段中的類isa指針

    • 如何訪問對象的屬性?指針名->屬性名;本質:根據指針名找到指針指向的對象,再根據屬性名查找來訪問對象的屬性值

    • 如何調用方法?[指針名 方法];本質:根據指針名找到指針指向的對象,再發現對象須要調用方法,再經過對象的isa指針找到代碼段中的類,再調用類裏面方法

  • 爲何不把方法存儲在對象中?

    • 由於以類爲模版建立的對象只有屬性可能不相同,而方法相同,若是堆區的對象裏面也保存方法的話就會很重複,浪費了堆空間,所以將方法存儲與代碼段

    • 因此一個類建立的n個對象的isa指針的地址值都相同,都指向代碼段中的類地址

作個小實驗

#import <Foundation/Foundation.h>
@interface Person : NSObject{
    @public
    int _age;
    NSString *_name;
    int *p;
}

-(void)sayHi;
@end

@implementation Person

-(void)sayHi{
    NSLog(@"Hi, %@",_name);
}

@end

int main(int argc, const char * argv[]) {
    Person *p1 = [Person new];
    Person *p2 = [Person new];
    Person *p3 = [Person new];
    p1->_age = 20;
    p2->_age = 20;

    [p1 sayHi];
    [p2 sayHi];
    [p3 sayHi];

    return 0;
}
Person  *p1 = [Person new];

這句代碼在內存分配原理以下圖所示

p1

結論

p1

p3

能夠 看到Person類的3個對象p一、p二、p3的isa的值相同。

相關文章
相關標籤/搜索