內(nèi)存中的五大區(qū)域.
一、棧區(qū)
又稱 堆棧 瘾境,由編譯器自動(dòng)分配釋放越除,是用戶存放程序臨時(shí)創(chuàng)建的 局部變量 ,也就是說我們函數(shù)括弧“{}” 中定義的變量(但不包括 static 聲明的變量, static 意味著在數(shù)據(jù)段中存放變量)棒坏。除此以外, 在函數(shù)被調(diào)用時(shí),其參數(shù)也會(huì)被壓入發(fā)起調(diào)用的進(jìn)程棧中,并且待到調(diào)用結(jié)束后,函數(shù)的返回值 也會(huì)被存放回棧中臭挽。
由于 棧 的后進(jìn)先出特點(diǎn),所以 棧 特別方便用來(lái)保存/恢復(fù)調(diào)用現(xiàn)場(chǎng)。從這個(gè)意義上講,我們可以把 堆棧 看成一個(gè)寄存絮爷、交換臨時(shí)數(shù)據(jù)的內(nèi)存區(qū)趴酣。
棧的地址空間在iOS中是以0X7開頭
- 棧 是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存區(qū)域
二坑夯、堆區(qū)
用于存放進(jìn)程運(yùn)行中被 動(dòng)態(tài)分配 的內(nèi)存段岖寞,堆區(qū)的大小并不固定,可動(dòng)態(tài)擴(kuò)張或縮減渊涝。當(dāng)進(jìn)程調(diào)用 alloc 等函數(shù)分配內(nèi)存時(shí),新分配的內(nèi)存就被動(dòng)態(tài)添加到堆上(堆被擴(kuò)張)床嫌;當(dāng)利用 realse 釋放內(nèi)存時(shí)跨释,被釋放的內(nèi)存從堆中被剔除(堆被縮減)。如果應(yīng)用程序沒有釋放掉厌处,操作系統(tǒng)會(huì)自動(dòng)回收鳖谈。變量通過 new、alloc阔涉、malloc缆娃、realloc 申請(qǐng)分配的內(nèi)存塊就存放在堆區(qū)捷绒。
- 由程序員分配釋放,分配方式類似于鏈表贯要,是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)暖侨,是不連續(xù)的內(nèi)存區(qū)域。
三崇渗、全局/靜態(tài)區(qū)
全局/靜態(tài)區(qū) 是存放 全局變量 和 靜態(tài)變量 的字逗。
已初始化的全局變量和靜態(tài)變量存放在一塊區(qū)域。data段
未初始化的全局變量和靜態(tài)變量在相鄰的另一塊區(qū)域宅广。BSS段
由 static 修飾的變量會(huì)成為靜態(tài)變量葫掉,該變量的內(nèi)存由全局/靜態(tài)區(qū)在 編譯階段 完成分配,且僅分配一次跟狱。
static 可以修飾局部變量也可以修飾全局變量俭厚。
- 全局/靜態(tài)區(qū) 的內(nèi)存在編譯階段完成分配,程序運(yùn)行時(shí)會(huì)一直存在內(nèi)存中驶臊,只有當(dāng)程序結(jié)束后才會(huì)由操作系統(tǒng)釋放挪挤。
四、常量區(qū) -- 數(shù)據(jù)段
常量區(qū) 是一塊比較特殊的存儲(chǔ)區(qū)资铡,常量區(qū)里面存放的是 常量 电禀,常量字符串就存放在常量區(qū)。
- 常量區(qū) 的內(nèi)存在 編譯階段 完成分配笤休,程序運(yùn)行時(shí)會(huì)一直存在內(nèi)存中尖飞,只有當(dāng)程序結(jié)束后才會(huì)由操作系統(tǒng)釋放。
五店雅、代碼區(qū) -- 代碼段
代碼區(qū) 是用來(lái)存放 可執(zhí)行文件的操作指令(存放函數(shù)的二進(jìn)制代碼)政基,其實(shí)就是存放程序的所有代碼。代碼區(qū) 需要防止在運(yùn)行時(shí)被非法修改闹啦,所以只準(zhǔn)許讀取操作沮明,而不允許寫入(修改)操作——它是不可寫的。
什么叫做類加載呢窍奋?
我們可以想象荐健,在創(chuàng)建對(duì)象的時(shí)候,肯定是需要訪問類的琳袄,聲明一個(gè)類的指針變量也會(huì)訪問類的江场。
當(dāng)程序運(yùn)行期間,當(dāng)某個(gè)類第一次被訪問到的時(shí)候窖逗,會(huì)將這個(gè)類存儲(chǔ)到內(nèi)存中的代碼段區(qū)域址否,這個(gè)過程就叫做類加載。
只有類在第一次被訪問的時(shí)候碎紊,才會(huì)做類加載佑附。
一旦類被加載到代碼段以后樊诺,直到程序結(jié)束的時(shí)候才會(huì)被釋放。
對(duì)象在內(nèi)存中如何存儲(chǔ)的
假設(shè)下面這句代碼寫在函數(shù)之中:
Person *p1 = [Person new];
Person *p1 會(huì)在棧內(nèi)存中申請(qǐng)一個(gè)空間音同,在棧內(nèi)存中聲明一個(gè)Person類型的指針變量p1词爬。p1是一個(gè)指針變量,那么只能存儲(chǔ)地址瘟斜。
[Person new]缸夹,真正在內(nèi)存中創(chuàng)建對(duì)象的其實(shí)是這句代碼。
new做的事情螺句,
- 第一是在堆內(nèi)存中申請(qǐng)1塊合適大小的空間虽惭;
- 第二是在這個(gè)空間中根據(jù)類的模板創(chuàng)建對(duì)象,類模板中定義了什么屬性蛇尚,就把這些屬性依次的聲明在對(duì)象之中; 對(duì)象中還有另外一個(gè)屬性芽唇,叫做isa,它是一個(gè)指針取劫,這個(gè)指針指向這個(gè)對(duì)象所屬的類在代碼段中的地址匆笤;
- 第三是初始化對(duì)象的屬性。如果屬性的類型是基本數(shù)據(jù)類型谱邪,那么賦值為0炮捧,如果屬性的類型是C語(yǔ)言的指針類型,那么就賦值為NULL惦银,如果屬性的類型是OC的類指針類型咆课,那么就賦值為nil;
- 第四是返回對(duì)象的地址扯俱,將這個(gè)地址賦值給p1书蚪。
注意:
對(duì)象中只有屬性,而沒有方法迅栅。只有自己所屬類的屬性外加一個(gè)isa指針指向代碼段中的類殊校;
- 如何訪問對(duì)象的屬性
指針名(對(duì)象名)->屬性名;
根據(jù)指針找到指針指向的對(duì)象读存,再找到對(duì)象中的屬性來(lái)訪問 - 如何調(diào)用方法
[指針名(對(duì)象名) 方法名];
先根據(jù)指針名找到對(duì)象为流,對(duì)象發(fā)現(xiàn)要調(diào)用方法,再根據(jù)對(duì)象的isa指針找到類让簿,然后調(diào)用類里的方法
對(duì)象作為類的屬性
為什么不把方法存儲(chǔ)在對(duì)象中敬察?
因?yàn)槊恳粋€(gè)對(duì)象的方法的代碼實(shí)現(xiàn)都是一模一樣的,沒有必要為每一個(gè)對(duì)象都保存一個(gè)方法拜英,這樣的話就太浪費(fèi)空間了静汤,既然都一樣琅催,那么就保存一份就可以了居凶。
對(duì)象的屬性的默認(rèn)值.
如果我們創(chuàng)建1個(gè)對(duì)象,沒有為對(duì)象的屬性賦值. 那么這個(gè)對(duì)象的屬性是有值的.
如果屬性的類型是基本數(shù)據(jù)類型 默認(rèn)值是0
如果屬性的類型是C指針類型 那么默認(rèn)值是NULL
如果屬性的類型是OC指針類型 那么默認(rèn)值是nil
nil虫给,Nil,NULL侠碧,NSNull抹估,kCFNull 區(qū)別
- Objective-C實(shí)例對(duì)象指針空值: NSSring *str = nil;
- Nil 類對(duì)象指針空值: Class class = Nil弄兜;
- NULL C指針空值: char *p = NULL药蜻; 宏 NULL等價(jià)于0
只能作為指針變量的值,代表指針不指向內(nèi)存中的任何一塊空間. - NSNull 是一個(gè)Objective-C繼承NSObject的類,多用于數(shù)組字典里面的空值
kCFNull 是NSNull的單例 [NSNull null]