天天看點

iOS: ARC & MRC下string記憶體管理政策探究

  

  前兩天跟同僚争論一個關于NSString執行copy操作以後是否會發生變化,兩個人整了半天,最後寫代碼驗證了一下,發現原來NSString操作沒我們想的那麼簡單,下面就讓我們一起看看NSString和NSMutableString在MRC下執行retain,copy,mutableCopy,以及ARC下不同的修飾__weak, __strong修飾指派究竟發生了什麼。

一、驗證代碼如下:

iOS: ARC & MRC下string記憶體管理政策探究
iOS: ARC & MRC下string記憶體管理政策探究

testStringAddress

  代碼中最開始定義了兩個int型的變量,主要是為了列印出目前函數的棧位址,順便驗證了一下記憶體中棧是從高位址向低位址生長的。使用預編譯宏#if __has_feature(objc_arc)來檢測目前是否是ARC環境,并根據不同環境寫了不同的測試代碼。

  通過在testStringAddress最後添加斷點,在lldb指令行下通過“p”指令輸出變量對應的位址,例如:檢視str指向的記憶體位址和内容,輸入"p str"即可。

  調試環境xCode6 beta4,iOS8 SDK。

二、MRC下執行情況

  執行結果如下圖所示:

iOS: ARC & MRC下string記憶體管理政策探究

  解釋一下上圖的内容:

  1、第一部分

  “p &str”表示列印str這個變量本身的位址,“p str”表示列印str指向的内容的位址。如上圖所示,"p &str"列印出來的結果是0xbff0aff8,局部變量b的位址為0xbff0affc,我們可以看出這兩者的記憶體位址是相連,因為他們都是函數體内部局部變量。而“p str”列印出來的結果是0x000a7048,說明str指向的内容的存儲區域和函數局部變量不在一起。

  2、第二部分

  c是我在函數中定義的一個static變量,“p &c”列印出來的位址為0x000a778c,觀察可知變量c和函數變量也不在一起。static變量在程式運作過程中隻會有一個,位于程式的靜态變量區。

  3、第三部分

  str的定義為“NSString *str = @"Hello World";”,通過調試發現str指向的内容為0x000a7048,且此時對str執行的retain和copy操作得到的結果位址均為0x000a7028。而執行mutableCopy後得到的NSString的位址為0x7974a110,和str以及retain,copy操作得到的位址不在一起。

  總結:形如@“Hello World”形式的變量在程式的常量區,而NSString在針對常量區的對象首次執行retain和copy時建立新對象,之後執行同類操作則發揮之前建立的對象,mutableCopy操作則在其他地方建立了一個對象,并使用str完成了初始化操作。

  4、第四部分

  str2定義為“NSString *str2 = [NSString stringWithFormat:@"Hello world"];”,列印結果發現str2指向的内容的位址為0x79749000,執行retain操作得到的string的指向内容的位址為0x7974a5c0,copy操作得到的位址也是0x7974a5c0,測試發現之後再對str2執行copy操作均會得到相同的位址。這塊兒貌似跟我們平時常念的“retain增加引用技術,copy建立新的對象”的觀念不符。對str2執行mutableCopy得到的位址為0x7974a380,重新建立了一個對象,符合我們的預期。

  總結:使用stringWithFormat方式建立的NSString對象預設在堆上,對這一類對象首次執行retain或copy操作時會建立一份拷貝,後續所有的retain和copy均會指向之前建立的同一個拷貝,無論何時執行mutableCopy操作均會建立新的對象。

  5、第五部分

  mutableStr的定義為“[NSMutableString stringWithString:@"hello world"];”,列印結果發現對mutableStr執行retain操作得到對象的位址和mutableStr相同,執行copy操作會建立新的對象,執行mutableCopy操作也會建立新的對象。

  總結:使用stringWithString方式建立的NSMutableString對象預設在堆上,對NSMutableString執行retain時不會建立新對象,執行copy和mutableCopy均會建立新的對象。

  觀察以上對象位址,大緻可以分為四個區間0x000a70xx,0x000a78xx,0x7974xxxx,0xbff5xxxx,其實它們分别依次代表四個不同的記憶體段常量區,靜态變量區,堆區,棧區。

三、ARC下執行情況

  執行結果如下圖:

iOS: ARC & MRC下string記憶體管理政策探究

  分析方法和第一部分一樣,這裡就不重複了。

  總結:

  1、針對常量區的NSString對象,執行weak,strong指派活着copy操作隻會生成一份拷貝,每次執行mutableCopy時均會建立新的對象。

  2、針對堆上的NSString對象執行weak,strong,copy操作時隻會建立一份拷貝,後續所有操作均得到相同的對象,每次執行mutableCopy時均會建立新的對象。

  3、針對NSMutableString對象首次執行weak,strong操作隻會建立一份拷貝,後續所有操作均得到相同對象,每次執行copy和mutableCopy操作均會建立新的對象。

四、總結

  綜上ARC和MRC下NSString,NSMutableString執行retain,copy,mutableCopy,weak,strong操作時記憶體情況見下表格:

iOS: ARC & MRC下string記憶體管理政策探究
iOS: ARC & MRC下string記憶體管理政策探究

  轉載請著名出處,有什麼問題歡迎留言

  如果覺得本文幫到了你,請推薦給身邊的朋友

部門招人: 進階iOS、Android、前端開發,有意私聊,部落客請你喝️

如果覺得本文幫到了你,記得點贊哦,當然也可以請部落客喝一杯豆漿

微信二維碼

QQ二維碼

繼續閱讀