NSSting內存
- 棧區(qū)(stack): 這個一般由編譯器操作庇楞,或者說是系統(tǒng)管理憋活,會存一些局部變量铝耻,函數(shù)跳轉跳轉時現(xiàn)場保護(寄存器值保存于恢復)猪落,這些系統(tǒng)都會幫我們自動實現(xiàn)贞远,無需我們干預。 所以大量的局部變量笨忌,深遞歸兴革,函數(shù)循環(huán)調用都可能耗盡棧內存而造成程序崩潰
- 堆區(qū)(heap): 一般由程序員管理,比如alloc申請內存,free釋放內存杂曲。我們創(chuàng)建的對象也都放在這里
- 全局區(qū)(靜態(tài)區(qū) static):全局變量和靜態(tài)變量的存儲是放在一塊的庶艾,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域擎勘。 - 程序結束后有系統(tǒng)釋放咱揍。注意:在嵌入式系統(tǒng)中全局區(qū)又可分為未初始化全局區(qū):.bss段 和初始化全局區(qū):data段。舉例:int a;未初始化的棚饵。int a = 10;已初始化的煤裙。
- 常量區(qū):常量字符串就是放在這里的,還有const常量
- 代碼區(qū):存放代碼噪漾,app程序會拷貝到這里
__NSCFConstantString顯然是常量字符串硼砰,地址0x10c843820自然就是存儲在常量區(qū)。
__NSCFString表示為oc對象欣硼,NSString就是封裝的CFString题翰,0x6000000315c0地址顯示這個字符串對象存儲在堆中。
NSTaggedPointerString這個類表示這是字符串的一種指針Tagged Pointer诈胜,0xa636261646362617這個地址為什么如此與眾不同呢豹障,接下來我們就簡單介紹這鐘字符串的存儲指針。
在蘋果推出了 采用64位架構的A7雙核處理器 iphone 5s的時候焦匈,為了節(jié)省內存和提高執(zhí)行效率血公,蘋果提出了Tagged Pointer的概念。先看看原有的對象為什么會浪費內存缓熟。假設要存儲一個 NSNumber 對象累魔,其值是一個整數(shù)。正常情況下够滑,如果這個整數(shù)只是一個 NSInteger 的普通變量垦写,那么它所占用的內存是與CPU的位數(shù)有關,在32位CPU下占4個字節(jié)版述,在64位CPU下是占8個字節(jié)的。而指針類型的大小通常也是與CPU位數(shù)相關寞冯,一個指針所占用的內存在32位CPU下為4個字節(jié)渴析,在64位CPU下也是8個字節(jié)。所以一個普通的iOS程序吮龄,如果沒有Tagged Pointer對象俭茧,從32位機器遷移到64位機器中后,雖然邏輯沒有任何變化漓帚,但這種NSNumber母债、NSDate一類的對象所占用的內存會翻倍。
對于以前的@""符號創(chuàng)建的字符串還是常量字符串,這個沒有改變毡们,但是采用stringWithFormat 等NSString方法的創(chuàng)建字符串對象則有了區(qū)別迅皇。
在蘋果的64位OC實現(xiàn)中,若對象指針的二進制第一位是1衙熔,則該指針為Tagged Pointer登颓。
例如0xa000000000000311其中a的2進制為1010,第一位1表示這是Tagged Pointer,010表示這是一個NSTaggedPointerString類红氯;這個地址最后一位表示字符串的數(shù)目框咙,這里是0001表示有1位字符串;其中真正用來存儲的位數(shù)只有中間的14位16進制痢甘。這個地址本身其實就存儲了字符串的值喇嘱,可以說是存儲在&strS內存中值,只是偽裝成了地址塞栅,它不需要存儲在數(shù)據區(qū)者铜,也不需要申請堆空間。
NSTaggedPointerString的存儲有三種編碼方式:ASCII碼构蹬,六位編碼王暗,五位編碼。
ASCII碼
我們發(fā)現(xiàn)NSTaggedPointerString存儲內容除去第一位和最后一位庄敛,其實只有中間的14位16進制字符俗壹,再看ascll碼由8位二進制組成,所以這里(14*4) / 8=7藻烤,用8位的ascll碼的話最多可以存儲7個字符绷雏。字符串數(shù)目0~7之間
[NSString stringWithFormat:@"1"]輸出的地址 0xa000000000000311,其中31的2進制是0011 0001怖亭,在ascll碼表里查找發(fā)現(xiàn)正是對應著“1”涎显;
六位編碼:
NSTaggedPointerString 采用六位二進制編碼,(14*4)/6=9.333…,可以看出最多存儲9位字符兴猩。字符數(shù)目8~9
五位編碼:
采用五位二進制編碼期吓,(14*4)/5 = 11.2,可以看出這種編碼最多存儲11位字符倾芝。字符數(shù)目在10~11
NSTaggedPointerString 存儲編碼中的六位和五位編碼都是根據通常代碼中字母使用頻率來排序的讨勤,但并不是一成不變的,apple會持續(xù)更新并統(tǒng)計字母使用頻率晨另,系統(tǒng)每次升級都可能不一樣潭千,當前第一位是字母e,之后是i,l借尿,o刨晴,t…屉来;這兩種編碼是從左向右的;根據編碼位數(shù)我們顯然也能推測出并不是所有字符都可以進行ascll或者六位五位編碼的狈癞,當出現(xiàn)這樣不能編碼的時候茄靠,系統(tǒng)也就不會使用NSTaggedPointerString類。