堆和棧的概念區(qū)別
堆: 是大家共有的空間驻襟,分全局堆和局部堆憨募。全局堆就是所有沒有分配的空間薯鳍,局部堆就是用戶分配的空間。堆在操作系統(tǒng)對(duì)進(jìn)程 初始化的時(shí)候分配月而,運(yùn)行過程中也可以向系統(tǒng)要額外的堆汗洒,但是記得用完了要還給操作系統(tǒng),要不然就是內(nèi)存泄漏父款。堆里面一般 放的是靜態(tài)數(shù)據(jù)溢谤,比如static的數(shù)據(jù)和字符串常量等瞻凤,資源加載后一般也放在堆里面。一個(gè)進(jìn)程的所有線程共有這些堆 世杀,所以對(duì)堆的操作要考慮同步和互斥的問題阀参。程序里面編譯后的數(shù)據(jù)段都是堆的一部分。
棧: 是個(gè)線程獨(dú)有的瞻坝,保存其運(yùn)行狀態(tài)和局部自動(dòng)變量的蛛壳。棧在線程開始的時(shí)候初始化,每個(gè)線程的検疲互相獨(dú)立,因此 伐憾,棧是 thread safe的勉痴。每個(gè)c++對(duì)象的數(shù)據(jù)成員也存在在棧中,每個(gè)函數(shù)都有自己的棧树肃,棧被用來在函數(shù)之間傳遞參數(shù)蒸矛。操作系統(tǒng)在切換線程的時(shí)候會(huì)自動(dòng)的切換棧,就是 切換ss/esp寄存器胸嘴。棾樱空間不需要在高級(jí)語(yǔ)言里面顯式的分配 和釋放。支持的數(shù)據(jù)有限劣像,一般是整數(shù)乡话,指針,浮點(diǎn)數(shù)等系統(tǒng)直接支持的數(shù)據(jù)類型耳奕, 并不直接支持其他的數(shù)據(jù)結(jié)構(gòu)绑青。
預(yù)備知識(shí)—程序的內(nèi)存分配
1、棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放屋群,存放函數(shù)的參數(shù)值闸婴,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧芍躏。
2邪乍、堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放对竣,程序結(jié)束時(shí)可能由OS回收庇楞。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表否纬。
3姐刁、全局(靜態(tài))區(qū)包含下面兩個(gè)分區(qū):
- 數(shù)據(jù)區(qū):數(shù)據(jù)段用來存放可執(zhí)行文件中已初始化全局變量,換句話說就是存放程序靜態(tài)分配的變量和全局變量烦味。
- BSS區(qū):BSS段包含了程序中未初始化全局變量聂使。
4壁拉、文字常量區(qū) —常量字符串就是放在這里的。程序結(jié)束后由系統(tǒng)釋放柏靶。
5弃理、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。
關(guān)于字符串
/*
static與const組合:在每個(gè)文件都需要定義一份靜態(tài)全局變量屎蜓。
extern與const組合:只需要定義一份全局變量痘昌,多個(gè)文件共享。
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的
這個(gè)我在沒有創(chuàng)建上面的控制器時(shí)po的驻啤。
0xa000000646464644
po出也是dddd。
所以我的理解是string2,3,4的指向堆區(qū)荐吵,因?yàn)樽址嬖诔A繀^(qū)骑冗,所以它們都是指向常量區(qū)的字符串。
但是為什么我打印的常量dddd -> 0x104420b70
先煎,和string2贼涩,3,4的0xa000000646464644
不一樣薯蝎。希望有大神能告訴我一下遥倦。
關(guān)于對(duì)象
-(void) testObject{
//對(duì)象的創(chuàng)建都是存放在堆區(qū)中,如果是局部變量占锯,因?yàn)锳RC的存在谊迄,所以不用程序員再手動(dòng)釋放,過了作用域obj1烟央,2统诺,3指向的內(nèi)存都會(huì)被釋放。
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 //對(duì)象原來的地址釋放掉
(lldb) po &obj2
0x00007fff57aecc10