iOS的關(guān)于堆區(qū)和棧區(qū)

堆和棧的概念區(qū)別

堆: 是大家共有的空間,分全局堆和局部堆。全局堆就是所有沒有分配的空間,局部堆就是用戶分配的空間。堆在操作系統(tǒng)對進程 初始化的時候分配,運行過程中也可以向系統(tǒng)要額外的堆,但是記得用完了要還給操作系統(tǒng),要不然就是內(nèi)存泄漏。堆里面一般 放的是靜態(tài)數(shù)據(jù),比如static的數(shù)據(jù)和字符串常量等,資源加載后一般也放在堆里面。一個進程的所有線程共有這些堆 ,所以對堆的操作要考慮同步和互斥的問題。程序里面編譯后的數(shù)據(jù)段都是堆的一部分。

棧: 是個線程獨有的,保存其運行狀態(tài)和局部自動變量的。棧在線程開始的時候初始化,每個線程的?;ハ嗒毩?,因此 ,棧是 thread safe的。每個c++對象的數(shù)據(jù)成員也存在在棧中,每個函數(shù)都有自己的棧,棧被用來在函數(shù)之間傳遞參數(shù)。操作系統(tǒng)在切換線程的時候會自動的切換棧,就是 切換ss/esp寄存器。??臻g不需要在高級語言里面顯式的分配 和釋放。支持的數(shù)據(jù)有限,一般是整數(shù),指針,浮點數(shù)等系統(tǒng)直接支持的數(shù)據(jù)類型, 并不直接支持其他的數(shù)據(jù)結(jié)構(gòu)。

預(yù)備知識—程序的內(nèi)存分配

1、棧區(qū)(stack)— 由編譯器自動分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

2、堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時可能由OS回收。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表。

3、全局(靜態(tài))區(qū)包含下面兩個分區(qū):

  • 數(shù)據(jù)區(qū):數(shù)據(jù)段用來存放可執(zhí)行文件中已初始化全局變量,換句話說就是存放程序靜態(tài)分配的變量和全局變量。
  • BSS區(qū):BSS段包含了程序中未初始化全局變量。

4、文字常量區(qū) —常量字符串就是放在這里的。程序結(jié)束后由系統(tǒng)釋放。

5、程序代碼區(qū)—存放函數(shù)體的二進制代碼。

內(nèi)存圖.png

關(guān)于字符串

/*
 static與const組合:在每個文件都需要定義一份靜態(tài)全局變量。
 extern與const組合:只需要定義一份全局變量,多個文件共享。
 static和extern定義的變量都在全局(靜態(tài))區(qū)
 */
//靜態(tài)變量
static  LMClass *obj4 ;
//全局靜態(tài)變量
//extern作用:只是用來獲取全局變量(包括全局靜態(tài)變量)的值,不能用于定義變量
extern NSString *externString = @"dddd";

int myInt = 20;//全局初始化區(qū)(數(shù)據(jù)區(qū))
NSString *str;//全局未初始化區(qū)(BSS區(qū))

-(void) testString{
    NSString *string = @"dddd";
    NSLog(@"dddd -> %p",@"dddd"); //dddd是常量字符串,存在常量區(qū)
    NSLog(@"string->%p",string); //string指針存在棧區(qū), 指針指向常量區(qū)
    NSLog(@"Int -> %u",0xa5a5a5a5);
    //string2在棧中,指向堆區(qū)的地址
    NSString *string2 = [[NSString alloc] initWithFormat:@"dddd"];
    NSLog(@"string2-> %p",string2);
        
    NSString *string3 = [NSString stringWithFormat:@"dddd"];
    NSLog(@"string3 -> %p", string3);
    //    string3 = nil;
    NSLog(@"string3 -> %p", string3);
    //string2 和 string3 都是指向同一地址
    //    string2 = nil;
    NSString *string4 = [string3 copy];
    //string4 也和 string2,3地址一樣
    NSLog(@"string4 -> %p", string4);
    
    //externString是指向常量區(qū)
    NSLog(@"externString ->%p", externString);
}

dddd -> 0x104420b70 string->0x104420b70 Int -> 2779096485 string2-> 0xa000000646464644 string3 -> 0xa000000646464644 string3 -> 0xa000000646464644 string4 -> 0xa000000646464644 externString ->0x10ecfab70
這圖片是在當(dāng)前控制器po的

在字符串的控制器.png

這個我在沒有創(chuàng)建上面的控制器時po的。

屏幕快照 2017-04-08 下午8.07.53.png

0xa000000646464644po出也是dddd。
所以我的理解是string2,3,4的指向堆區(qū),因為字符串存在常量區(qū),所以它們都是指向常量區(qū)的字符串。

但是為什么我打印的常量dddd -> 0x104420b70,和string2,3,4的0xa000000646464644不一樣。希望有大神能告訴我一下。

關(guān)于對象

-(void) testObject{
    //對象的創(chuàng)建都是存放在堆區(qū)中,如果是局部變量,因為ARC的存在,所以不用程序員再手動釋放,過了作用域obj1,2,3指向的內(nèi)存都會被釋放。
    LMClass *obj1 = [[LMClass alloc] init];
    NSLog(@"obj1->%p-----obj1指針%p",obj1, &obj1);
    
    LMClass *obj2 = [[LMClass alloc] init];
    NSLog(@"obj2->%p-----obj2指針%p",obj2, &obj2);
    
    LMClass *obj3 = [obj2 copy];
    NSLog(@"obj3->%p-----obj3指針%p",obj3, &obj3);
    
    //obj2釋放了,原來obj2指向的內(nèi)存成為空閑內(nèi)存
    obj2 = nil;
    
}

打印數(shù)據(jù)

obj1->0x6100000148b0-----obj1指針0x7fff57aecc18
obj2->0x618000014b30-----obj2指針0x7fff57aecc10
obj3->0x600000014b80-----obj3指針0x7fff57aecc08
(lldb) po obj2
 nil
(lldb) po 0x618000014b30
107202383792720 //對象原來的地址釋放掉
(lldb) po &obj2
0x00007fff57aecc10
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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