Objective-C記憶體管理之引用計數,objective-c記憶體管理

來源:互聯網
上載者:User

Objective-C記憶體管理之引用計數,objective-c記憶體管理

  初學者在學習Objective-c的時候,很容易在記憶體管理這一部分陷入混亂狀態,很大一部分原因是沒有弄清楚引用計數的原理,搞不明白對象的引用數量,這樣就當然無法徹底釋放對象的記憶體了,蘋果官方文檔在記憶體管理這一部分說的非常簡單,只有三條準則:

  如果在寫代碼的時候遵守這些準則,可以避免記憶體泄露,但是如果僅靠對這些準則的“記憶”來寫代碼的話,恐怕自己心裡都不會有底,一旦遇到問題分析問題的時候很難從根本上找到問題出現的原因,本文分享了自己在理解引用計數時的分析過程,結合相關圖形,希望能讓大家深刻理解對象引用計數的原理。

遇到了問題?分析然後測試

  當前對象的引用計數是多少呢?

     為什麼要提出這個問題,因為很多人會搞混對象的指標數量與引用數量的關係,不理解這個問題就弄不明白對象的引用計數到底為多少,當然就無法正確釋放記憶體了。在說這個之前先簡單瞭解一下堆記憶體與棧記憶體的概念,

     變數名實際上是一個符號地址,在對程式編譯串連時由系統給每一個變數名分配一個記憶體位址。在程式中從變數中取值,實際上是通過變數名找到相應的記憶體位址,從其儲存單元中讀取資料。指標是一個特殊的變數,因為它存放的是一個變數的地址。如所示:

 

  上面這個記憶體模型相信大家都知道,指標與對象存在一個間接(指向)的關係,因此當指標指向一個對象的時候,很多人就會覺得這個指標引用到了該對象,進而就認為當指標指向一個對象的時候,該對象的引用計數就會加1,這種理解是一種感性的理解。實際上對於一個對象來說,它是不知道指向它的指標有多少個的,它的釋放僅僅依靠的是引用計數,那麼什麼是引用計數呢?在objective-c中,大部分對象都繼承於NSObject,NSObject包含一個用來儲存引用數量的欄位retainCount,說白了該欄位就是引用計數,NSObject類的部分定義如下:
- (id)retain;
- (oneway void)release;
- (id)autorelease;
- (NSUInteger)retainCount;
- (NSString *)description;

因此,為了便於理解,我們可以把NSObject簡化為如下模型:

 

  對象能否釋放就是判斷其引用次數是否為零,也就是判斷該對象的retainCount欄位是否等於0,而指向該對象指標數量跟該對象retainCount欄位的值並沒有關係,因此指標數量並不等於引用數量,當指標指向該對象的時候,僅僅是給該指標變數賦值了,並沒有修改對象的retainCount值,因此,指標指向一個對象的時候,該對象的引用計數是沒有改變的。

  以上面那段代碼為例,我們調用Test對象的new方法的時候,會自動將retainCount的值設定為1,當我們將test1賦值給test2的時候,只是一個指標賦值,並沒有修改對象的retainCount值,所以引用計數不變,依舊為1。

測試案例:

 1         Engine *engine1 = [Engine new]; 2         NSLog(@"通過new訊息建立對象engine1:"); 3         //輸出engine1指標地址 4         NSLog(@"engine1 address is %p.",engine1); 5         //輸出engine1的retainCount 6         NSLog(@"engine1 retainCount is %lu",(unsigned long)[engine1 retainCount]); 7          8         Engine *engine2 = engine1; 9         NSLog(@"將指標engine1複製給指標engine2:");10         //輸出engine2指標地址11         NSLog(@"engine2 address is %p.",engine2);12         //輸出engine1的retainCount13         NSLog(@"engine1 retainCount is %lu",(unsigned long)[engine1 retainCount]);14         //輸出engine2的retainCount15         NSLog(@"engine2 retainCount is %lu",(unsigned long)[engine2 retainCount]);16         17         Engine *engine3 = [engine1 retain];18         NSLog(@"通過retain訊息獲得對象engine3:");19         //輸出engine3指標地址20         NSLog(@"engine3 address is %p.",engine3);21         //輸出engine1的retainCount22         NSLog(@"engine1 retainCount is %lu",(unsigned long)[engine1 retainCount]);23         //輸出engine2的retainCount24         NSLog(@"engine2 retainCount is %lu",(unsigned long)[engine2 retainCount]);25         //輸出engine3的retainCount26         NSLog(@"engine3 retainCount is %lu",(unsigned long)[engine3 retainCount]);27         28         [engine2 release];29         NSLog(@"給對象engine2發送訊息release");30         NSLog(@"engine2 address is %p.",engine2);31         NSLog(@"engine2 retainCount is %lu.",(unsigned long)[engine2 retainCount]);

輸出結果如下:

  從上面的輸出結果可以得出以下幾點結論:

  因為這裡需要輸出引用計數,就沒有採用ARC,所以會有一個小問題,那就是當退出局部環境的時候,即使局部指標所指向的對象已被銷毀,局部指標變數的值仍然沒有改變,因此需要手動賦值為nil。如果採用ARC的話,會自動回收記憶體並將指標賦值為nil。

總結

  不管是直接通過指標賦值還是通過retain或者copy來保留對象,都會增加指向對象的指標數量,這些指標都指向同一塊記憶體位址,因為對象所分配的記憶體位址是不變的。

  指向對象的指標的多少跟引用計數沒有任何關係,但是通過retain、copy或release可以改變對象的引用計數。

  僅當引用計數為0時才會釋放對象佔用的記憶體空間。  

  哎,真是“落花有意流水無情”啊,哪怕再多的指標“愛上對象”,人家這輩子卻也只認引用計數。


objective-c引用計數的問題

myStr1 myStr2是常量字串直接指向靜態區

myStr3是自動釋放

這兩種形式的retainCount都是不可信的,也不是你該關注的
這種產生字串的方式無需你管理記憶體

只有alloc出來的initWithString才需要你手動release
你以上代碼做的事情是沒有實際意義的,NSString雖然產生的也可以說是類對象,但相對於其它oc對象的記憶體管理是比較特殊的,新手在不瞭解的情況下研究NSString只會對引用計數的理解更加混亂。
還是那句話,沒有特殊需求的話不要查看string的retaincount,沒有意義,你這些代碼不知道哪個教的,混淆視聽,誤人子弟。
 
Objective-C 中的引用計數問題

是指標指向的對象有引用計數
只要指標指向的地址相同,那麼引用計數相同
你的例子中,第二句話執行完之後,obj2和obj1的引用計數一樣,為1
執行完第三句以後,obj1自然變成了2,obj2也同時變成了2

可以通過調用對象的retainCount查看引用計數,e.g.
NSLog(@"%d", [obj2 retainCount]);
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.