iOS: ARC & MRC下string記憶體管理原則探究

來源:互聯網
上載者:User

iOS: ARC & MRC下string記憶體管理原則探究
前兩天跟同事爭論一個關於NSString執行copy操作以後是否會發生變化,兩個人整了半天,最後寫代碼驗證了一下,發現原來NSString操作沒我們想的那麼簡單,下面就讓我們一起看看NSString和NSMutableString在MRC下執行retain,copy,mutableCopy,以及ARC下不同的修飾__weak, __strong修飾賦值究竟發生了什麼。   一、驗證代碼如下:  複製代碼- (void)testStringAddress{    int a = 0;    int b = 0;        static int c = 0;        NSString *str = @"Hello World";    #if __has_feature(objc_arc)    __weak   NSString *weakStr = str;    __strong NSString *strongStr = str;#else    NSString *retainStr = [str retain];#endif        NSString *copyStr = [str copy];    NSMutableString *mutableCopyStr = [str mutableCopy];        // 驗證mutableCopy出來的是否是mutableString,如果不是執行此行會Crash    [mutableCopyStr appendFormat:@".."];    str = @"i'm changed";        NSString *str2 = [NSString stringWithFormat:@"Hello world"];    #if __has_feature(objc_arc)    __weak   NSString *weakStr2 = str2;    __strong NSString *strongStr2 = str2;#else    NSString *retainStr2 = [str2 retain];#endif        NSString *copyStr2 = [str2 copy];    NSString *copy2Str2 = [str2 copy];    NSString *mutableCopyStr2 = [str2 mutableCopy];    NSString *mutableCopy2Str2 = [str mutableCopy];    str2 = [[NSString alloc] initWithFormat:@"changed"];        NSMutableString *mutableStr = [NSMutableString stringWithString:@"hello world"];    #if __has_feature(objc_arc)    __weak   NSMutableString *weakMutableStr = mutableStr;    __strong NSMutableString *strongMutableStr = mutableStr;#else    NSMutableString *retainMutableStr = [mutableStr retain];#endif        NSMutableString *copyMutableStr = [mutableStr copy];    NSMutableString *copy2MutableStr = [mutableStr copy];    NSString *mutableCopyMutableStr = [mutableStr mutableCopy];    NSString *mutableCopy2MutableStr = [mutableStr mutableCopy];    [mutableStr appendFormat:@" apped something"]; #if __has_feature(objc_arc)    NSLog(@"\r str: %@,\r weakStr: %@,\r strongStr: %@,\r copyStr: %@,\r mutableCopyStr: %@", str, weakStr, strongStr, copyStr, mutableCopyStr);    NSLog(@"\r str2: %@,\r weakStr2: %@,\r strongStr: %@,\r copyStr2: %@,\r mutableCopyStr2: %@", str2, weakStr2, strongStr2, copyStr2, mutableCopyStr2);    NSLog(@"\r mutableStr: %@,\r weakMutableStr: %@\r strongMutableStr: %@,\r copyMutableStr: %@,\r mutableCopyMutableStr: %@", mutableStr, weakMutableStr, strongMutableStr, copyMutableStr, mutableCopyMutableStr);#else     NSLog(@"\r str: %@,\r retainStr: %@,\r copyStr: %@,\r mutableCopyStr: %@", str, retainStr, copyStr, mutableCopyStr);    NSLog(@"\r str2: %@,\r retainStr2: %@,\r copyStr2: %@,\r mutableCopyStr2: %@", str2, retainStr2, copyStr2, mutableCopyStr2);    NSLog(@"\r mutableStr: %@,\r retainMutableStr: %@,\r copyMutableStr: %@,\r mutableCopyMutableStr: %@", mutableStr, retainMutableStr, copyMutableStr, mutableCopyMutableStr);#endif}複製代碼  代碼中最開始定義了兩個int型的變數,主要是為了列印出當前函數的棧地址,順便驗證了一下記憶體中棧是從高地址向低地址生長的。使用先行編譯宏#if __has_feature(objc_arc)來檢測當前是否是ARC環境,並根據不同環境寫了不同的測試代碼。   通過在testStringAddress最後添加斷點,在lldb命令列下通過“p”命令輸出變數對應的地址,例如:查看str指向的記憶體位址和內容,輸入"p str"即可。   調試環境xCode6 beta4,iOS8 SDK。   二、MRC下執行情況   執行結果如所示:     解釋一下的內容:   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,其實它們分別依次代表四個不同的記憶體段常量區,靜態變數區,堆區,棧區。  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.