NSString在不同的初始化方式導致的神奇現(xiàn)象

本文主要是實驗了兩個不同的NSString初始化方法導致的奇怪現(xiàn)象,因為能力有限,只進行了一番簡單的解釋,拋磚引玉。最后附上了一些猜想,供君參考。

1.當NSString長度小于10時,不再遵循引用計數(shù)規(guī)則

如果不能理解【引用計數(shù)規(guī)則】可以參考下另一篇文章iOS中copy,strong,retain,weak和assign的區(qū)別。
實驗代碼如下

NSString *stringLess10 = [[NSString alloc] initWithUTF8String:"123456789"];
NSString *string1Less10 = [[NSString alloc] initWithUTF8String:"123456789"];
NSLog(@"stringLess10值地址%p,引用計數(shù)%@",stringLess10,[stringLess10 valueForKey:@"retainCount"]);
NSLog(@"string1Less10值地址%p,引用計數(shù)%@",string1Less10,[string1Less10 valueForKey:@"retainCount"]);

NSString *stringMore10 = [[NSString alloc] initWithUTF8String:"12345678910"];
NSString *string1More10 = [[NSString alloc] initWithUTF8String:"12345678910"];
NSLog(@"stringMore10值地址%p,引用計數(shù)%@",stringMore10,[stringMore10 valueForKey:@"retainCount"]);
NSLog(@"string1More10值地址%p,引用計數(shù)%@",string1More10,[string1More10 valueForKey:@"retainCount"]);

輸出結果:

stringLess10值地址0xa1ea1f72bb30ab19,引用計數(shù)18446744073709551615
string1Less10值地址0xa1ea1f72bb30ab19,引用計數(shù)18446744073709551615
stringMore10值地址0x6080000306e0,引用計數(shù)1
string1More10值地址0x6080000306a0,引用計數(shù)1

現(xiàn)象:stringLess10和string1Less10值地址相同且引用計數(shù)異常,但在字符串長度大于10的stringMore10和string1More10上這個現(xiàn)象就不存在了
解釋:當NSString長度小于10時不再遵循引用計數(shù)規(guī)則,Tagged Pointer技術對其進行了優(yōu)化?;疽馑季褪悄J會將一些長度小于10的字符串直接保存在指針上面,下次創(chuàng)建相同值的時候直接用同一份拷貝,這樣既減少了一次指針到值的訪問,又減少了一份內(nèi)存的占用。
深入資料:http://www.cocoachina.com/ios/20150918/13449.html

2.NSString直接字符串賦值的異常

實驗代碼:

NSString *stringWithOutInit = @"1234567891011";
NSLog(@"stringWithOutInit,值地址%p,引用計數(shù)%@",stringWithOutInit,[stringWithOutInit valueForKey:@"retainCount"]);

輸出結果:

stringWithOutInit,值地址0x1081f7180,引用計數(shù)18446744073709551615

現(xiàn)象:值地址相當靠前,如一般是0xa1ea1f72bb30ab19,而他是0x1081f7180。另外引用計數(shù)非常大。
解釋:直接字符串賦值和init系列初始化方法有所不同。前者創(chuàng)建的是一個常量,不遵循引用計數(shù)。且在App結束前不會被釋放掉。引用計數(shù)在這個不能被釋放的內(nèi)存塊上默認返回是一個很大的值
我們通過weak類型來接收這個值,并把stringWithOutInit設置nil,驗證原來的內(nèi)存塊是否會釋放
實驗代碼

__weak NSString *weakStr = stringWithOutInit;
stringWithOutInit = nil;
NSLog(@"weakStr指針地址%p,值地址%p,引用計數(shù)%@,值為%@", &weakStr,weakStr,[weakStr valueForKey:@"retainCount"],weakStr);

輸出:

weakStr值地址0x1081f7180,值為1234567891011

發(fā)現(xiàn)值地址就是之前stringWithOutInit的值地址,且值依舊存在。
現(xiàn)象:雖然只有弱指針指向這個內(nèi)存塊,但依舊有值存在,未被釋放。
解釋:因為常量的引用計數(shù)無限大,自然值就不會被釋放

3.附加猜測NSString內(nèi)存中的存儲方式

我們知道NSMutableString對象的指針地址和值地址分別在棧和堆上,那么我們可以通過他的指針地址和棧地址來猜測nsstring不同方式初始化的時候指針和值地址在堆還是在棧上
試驗代碼:

NSMutableString *mstr = [[NSMutableString alloc] initWithFormat:@"%@",@"asdfasdfffffff"];
    NSLog(@"mstr指針地址:%p 值地址%p,引用計數(shù)%@",&mstr,mstr,[mstr valueForKey:@"retainCount"]);
    NSLog(@"stringLess10指針地址:%p 值地址%p,引用計數(shù)%@",&stringLess10,stringLess10,[stringLess10 valueForKey:@"retainCount"]);
    NSLog(@"stringMore10指針地址:%p 值地址%p,引用計數(shù)%@",&stringMore10,stringMore10,[stringMore10 valueForKey:@"retainCount"]);
    NSLog(@"stringWithOutInit指針地址:%p 值地址%p,引用計數(shù)%@",&stringWithOutInit,stringWithOutInit,[stringWithOutInit valueForKey:@"retainCount"]);

輸出結果:

mstr指針地址:0x7fff51dbbaa8 值地址0x60800006bc00,引用計數(shù)1
stringLess10指針地址:0x7fff51dbbaf8 值地址0xa1ea1f72bb30ab19,引用計數(shù)18446744073709551615
stringMore10指針地址:0x7fff51dbbae8 值地址0x600000024a80,引用計數(shù)1
stringWithOutInit指針地址:0x7fff51dbbad0 值地址0x0,引用計數(shù)(null)

現(xiàn)象和結論:
指針地址都是12位且值都相近,所以NSString不管初始化如何指針依舊保存在棧上面。
stringMore10和mstr值地址相近,所以init初始化方式在長度大于10的時候默認值存放在堆上。
stringLess值地址10長度為16位,完全不在堆上。
stringWithOutInit值地址沒有,說明他也不在堆上面,且和stringLess值存儲方式不一樣。

交流qq:578172874
錯誤之處還希望能幫忙提出來,一起學習,O(∩_∩)O謝謝了

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • __block和__weak修飾符的區(qū)別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,585評論 0 6
  • 多線程、特別是NSOperation 和 GCD 的內(nèi)部原理。運行時機制的原理和運用場景。SDWebImage的原...
    LZM輪回閱讀 2,108評論 0 12
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 2,241評論 0 7
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛DE問候閱讀 1,835評論 0 4
  • 1.寫一個NSString類的實現(xiàn) +(id)initWithCString:(c*****t char *)nu...
    韓七夏閱讀 3,872評論 2 37

友情鏈接更多精彩內(nèi)容