說到iOS的內(nèi)存管理,大家首先想到的可能是引用計數(shù)相關(guān)的東西,而跟引用計數(shù)相關(guān)的內(nèi)存都是分布在堆區(qū)(heap),也就是說我們平時關(guān)注最多的部分都是堆區(qū)的內(nèi)存锤窑。其實(shí)在iOS系統(tǒng)中(其他操作系統(tǒng)也一樣)老玛,內(nèi)存的分布區(qū)域大致可以分為三個部分:棧區(qū)(stack),堆區(qū)(heap),和全局靜態(tài)區(qū)(global)乳乌。其中棧區(qū)主要存放局部變量和函數(shù)參數(shù)等相關(guān)變量,超出作用域之后自動釋放市咆,堆區(qū)存放alloc,new等關(guān)鍵字生成的對象汉操;全局靜態(tài)區(qū)主要存放靜態(tài)數(shù)據(jù),全局?jǐn)?shù)據(jù)和常量蒙兰,程序運(yùn)行之后一直存在磷瘤。分布如下圖所示:
在說內(nèi)存分布之前,先來理一理幾個概念:靜態(tài)數(shù)據(jù)搜变,全局?jǐn)?shù)據(jù)和常量采缚。定義在類外面的都是全局?jǐn)?shù)據(jù),前面加const的挠他,就是常量數(shù)據(jù)扳抽,加static的是靜態(tài)數(shù)據(jù)。
通過字符串的初始化殖侵,來分析內(nèi)存的分布
NSString* str1 = @"123";
NSLog(@"str1 = %p, str1 = %@",str1,str1);
NSString* str2 = @"123";
NSLog(@"str2 = %p, str2 = %@",str2,str2);
NSString* str3 = [[NSString alloc]initWithFormat:@"123"];
NSLog(@"str3 = %p, str3 = %@",str3,str3);
NSString* str4 = [[NSString alloc]initWithFormat:@"123"];
NSLog(@"str4 = %p, str4 = %@",str4,str4);
NSString* str5 = [[NSString alloc]initWithString:str3];
NSLog(@"str5 = %p, str5 = %@",str5,str5);
NSString* str6 = [[NSString alloc]initWithString:str3];
NSLog(@"str6 = %p,str6 = %@",str6,str6);
打印結(jié)果如下:
首先@"123"是字符串常量贸呢,被分配在內(nèi)存的常量區(qū); str2也指向了這個常量,所以str1和str2的對應(yīng)的指針是一樣的拢军。str3指向了一個alloc出來的對象楞陷,這個對象是被分配在堆內(nèi)存上的,所以str3和str2對應(yīng)的指針不一樣了茉唉」潭辏可能大家會感到奇怪,str4也指向了一個alloc出來的對象度陆,這個對象也是被分配在堆內(nèi)存上的艾凯,為什么會跟str3的指向相同呢?其實(shí)這是iOS系統(tǒng)對字符串內(nèi)存的優(yōu)化:如果一個字符串是通過一個字符串常量初始化而來的懂傀,那么這個字符串里面的值可以直接從常量區(qū)去拿趾诗,這樣就不需要為每一個在堆上面的字符串分配一塊兒新的內(nèi)存。str5和str6都是指向堆上面的內(nèi)存鸿竖,并且是通過變量來初始化的沧竟,所以對應(yīng)的指針不一樣铸敏。
上面一大段文字說的都是指針對應(yīng)的指向,而str1--str6本身是一個指針悟泵,又都是在函數(shù)中定義的杈笔,是局部變量,所以被分配到棧區(qū)糕非。綜上可以得出如下的內(nèi)存分布圖: