一概述
本文主要是關(guān)于基于64位系統(tǒng)下椒振,NSString對(duì)象的retainCount分析。
二內(nèi)容
1.以下對(duì)象的retainCount為18446744073709551615也就是2的64次方減一,也就是ULONG_MAX
// @"123456789"是一個(gè)字符串常量,數(shù)據(jù)保存在數(shù)據(jù)區(qū)帽借,不在堆區(qū)妓盲,是不可能
// 被釋放的,所以他的retainCount為ULONG_MAX檐迟,就算執(zhí)行release也不會(huì)有變化
// 這三個(gè)的內(nèi)存地址也是一樣的0x10bc89060补胚,他們的class類型都為__NSCFConstantString
NSString *name = @"123456789";
NSString * name = [NSString stringWithString:@"123456789"];
NSString * name = [[NSString alloc] initWithString:@"123456789"];
// 下面的內(nèi)存地址于上面的不一樣,為0xa1ea1f72bb30ab19追迟,class類型為NSTaggedPointerString
NSString * name = [NSString stringWithFormat:@"123456789"];
NSTaggedPointerString這個(gè)類表示這是字符串的一種指針Tagged Pointer溶其,在蘋果推出了 采用64位架構(gòu)的A7雙核處理器 iphone 5s的時(shí)候,為了節(jié)省內(nèi)存和提高執(zhí)行效率敦间,蘋果提出了Tagged Pointer的概念瓶逃,這是為了從32位機(jī)器遷移到64位機(jī)器中后節(jié)省內(nèi)存。在蘋果的64位OC實(shí)現(xiàn)中廓块,若對(duì)象指針的二進(jìn)制第一位是1厢绝,則該指針為Tagged Pointer。
例如0xa1ea1f72bb30ab19其中a的2進(jìn)制為1010,第一位1表示這是Tagged Pointer带猴,010表示這是一個(gè)NSTaggedPointerString類昔汉;這個(gè)地址最后一位表示字符串的數(shù)目,這里是0101表示有9位字符串拴清;其中真正用來存儲(chǔ)的位數(shù)只有中間的14位16進(jìn)制靶病。這個(gè)地址本身其實(shí)就存儲(chǔ)了字符串的值,可以說是存儲(chǔ)在&strS內(nèi)存中值口予,只是偽裝成了地址娄周,它不需要存儲(chǔ)在數(shù)據(jù)區(qū),也不需要申請(qǐng)堆空間沪停。
NSTaggedPointerString的存儲(chǔ)有三種編碼方式:ASCII碼煤辨,六位編碼,五位編碼。
六位編碼:
NSTaggedPointerString 采用六位二進(jìn)制編碼掷酗,(14*4)/6=9.333…,可以看出最多存儲(chǔ)9位字符调违。字符數(shù)目8~9
五位編碼:
采用五位二進(jìn)制編碼,(14*4)/5 = 11.2泻轰,可以看出這種編碼最多存儲(chǔ)11位字符技肩。字符數(shù)目在10~11
1.以下對(duì)象的retainCount為1,class類型都為__NSCFString
// @"hello boy %@"和@"jack"這兩個(gè)是字符串常量浮声,是無法修改的虚婿,所以由這兩個(gè)組成的是一個(gè)新的字符串就不能再他們基礎(chǔ)上修改得到,只能申請(qǐng)新的內(nèi)存泳挥,只能在堆里面申請(qǐng)然痊,所以這時(shí)產(chǎn)生的NSString對(duì)象的retainCount為1
NSString *name = [[NSString alloc] initWithFormat:@"hello boy %@",@"jack"];
// 比較之前使用的stringWithFormat參數(shù)的對(duì)象的retainCount于之不一樣,因?yàn)楝F(xiàn)在的字符串超過了9個(gè)屉符,所以無法使用NSTaggedPointerString來保存剧浸,只能申請(qǐng)新的內(nèi)存,所以這時(shí)產(chǎn)生的NSString對(duì)象的retainCount為1
NSString * name = [NSString stringWithFormat:@"1234567890"];
備注:因?yàn)閞etainCount返回的數(shù)據(jù)類型為NSUInteger矗钟,在64為系統(tǒng)中為8個(gè)字節(jié)無符號(hào)整數(shù)唆香,打印的時(shí)候需要使用%lu,如果使用%d吨艇,則本應(yīng)該輸出為2^64-1躬它,會(huì)變成-1。
這是因?yàn)槎校瑪?shù)據(jù)保存的方式是補(bǔ)碼冯吓。正整數(shù)的原碼、反碼疮跑、補(bǔ)碼完全一樣组贺,即符號(hào)位固定為0,數(shù)值位相同祸挪;負(fù)整數(shù)的符號(hào)位固定為1锣披,由原碼變?yōu)檠a(bǔ)碼時(shí),規(guī)則如下: 1原碼符號(hào)位1不變贿条,整數(shù)的每一位二進(jìn)制數(shù)位求反,得到反碼增热;2反碼符號(hào)位1不變整以,反碼數(shù)值位最低位加1,得到補(bǔ)碼峻仇。無符號(hào)2^64-1保存的二進(jìn)制格式為64個(gè)1公黑,如果按照有符號(hào)打印,按照補(bǔ)碼反推,1反碼符號(hào)位1不變凡蚜,反碼數(shù)值位最低位減一1得到63個(gè)1加上最后一個(gè)0人断,2原碼符號(hào)位1不變,整數(shù)的每一位二進(jìn)制數(shù)位求反得到開頭為1中間為62個(gè)0末尾為1的二進(jìn)制數(shù)朝蜘,由于打印是%d恶迈,所以取32個(gè)低位數(shù),得到31個(gè)0和末尾一個(gè)1谱醇,剛好是-1.