iOS中引用計數記憶體管理機制分析,ios記憶體管理

來源:互聯網
上載者:User

iOS中引用計數記憶體管理機制分析,ios記憶體管理

    在 iOS 中引用計數是記憶體的管理方式,雖然在 iOS5 版本中,已經支援了自動引用計數管理員模式,但理解它的運行方式有助於我們瞭解程式的運行原理,有助於 debug 程式。

   作業系統的記憶體管理分成堆和棧。

 

   在堆中分配的記憶體,都試用引用計數模式;在棧中則不是。

 

   NSString 定義的對象是儲存在棧中,所以它沒有引用計算。看一些書上說它的引用計算會是 fffffffff 最大整數,測試的結果顯示它是- 1. 對該對象進行 retain 操作,不好改變它的 retainCount 值。

 

   MutableNSString 定義的對象,需要先分配堆中的記憶體空間,再初始化才能使用。它是採用引用計數管理記憶體的。對該對象做 retainCount 操作則每次增加一個。

 

   其實,引用計數是對記憶體地區的空間管理方式,是應從記憶體塊的視角去看的。任何對象都是指向它的指標,有多少個指標指向它,就有多少個引用計算。

   如果沒有任何指標指向該記憶體塊了,很明顯,該記憶體塊就沒有對象引用了,引用計算就是 0, 系統會人為該記憶體地區已經空閑,於是立即清理,也就是更新一下管理堆的鏈表中某個標示位。

 

 

(miki西遊 @mikixiyou 原文 連結: http://mikixiyou.iteye.com/blog/1592958 )

 

     測試方法如下:

 

     在 xcode 中建立一個非 arc 的項目,單視圖即可。建立一個按鈕的操作方法。

 

     - (IBAction)testRC:(id)sender {

 

     NSInteger i;

     i=self.i_test;

 

     if((i%2)==1)

     {

     NSString * str1=@"welcome";

     NSString * str2=@"mlgb";

     NSString * str3;

     NSString * str4=@"welcome";

     NSLog(@"str1 addr is %p",str1);

     NSLog(@"str2 addr is %p",str3);

     NSLog(@"str3 addr is %p",str3);

     NSLog(@"str4 addr is %p",str4);

 

     NSLog(@"str1 retainCount is %i",[str1 retainCount]);

     NSLog(@"str2 retainCount is %i",[str2 retainCount]);

     //NSLog(@"str3 retainCount is %i",[str3 retainCount]); 該使用會導致 crash ,因為 str3 沒有指向任何記憶體地區。

 

 

     str3=[str1 retain];

     NSLog(@"str3=[str1 retain];");

     NSLog(@"str1 retainCount is %i",[str1 retainCount]);

     NSLog(@"str3 retainCount is %i",[str3 retainCount]);

     str3=[str2 retain];

     NSLog(@"str3=[str2 retain];");

     NSLog(@"str2 retainCount is %i",[str1 retainCount]);

     NSLog(@"str3 retainCount is %i",[str2 retainCount]);

 

     /*

     結果如下:

     2012-07-14 11:07:38.358 testMem[878:f803] str1 addr is 0x3540

     2012-07-14 11:07:38.360 testMem[878:f803] str2 addr is 0x0

     2012-07-14 11:07:38.361 testMem[878:f803] str3 addr is 0x0

     2012-07-14 11:07:38.362 testMem[878:f803] str4 addr is 0x3540

 

     在棧中,內容相同的對象 str1 和 str4 ,都分配在一個記憶體地區中,這點是 c 編譯器的功能,有利於記憶體使用量和效率。

 

 

     2012-07-14 11:07:38.363 testMem[878:f803] str1 retainCount is -1

     2012-07-14 11:07:38.364 testMem[878:f803] str2 retainCount is -1

     2012-07-14 11:07:38.365 testMem[878:f803] str3=[str1 retain];

     2012-07-14 11:07:38.366 testMem[878:f803] str1 retainCount is -1

     2012-07-14 11:07:38.367 testMem[878:f803] str3 retainCount is -1

     2012-07-14 11:07:38.367 testMem[878:f803] str3=[str2 retain];

     2012-07-14 11:07:38.368 testMem[878:f803] str2 retainCount is -1

     2012-07-14 11:07:38.369 testMem[878:f803] str3 retainCount is -1

 

     */

}

else

{

 

 

    NSMutableString * mstr1=[[NSMutableString alloc] initWithString: @"welcome" ];

    NSMutableString * mstr2=[[ NSMutableString alloc ] initWithString : @"mlgb" ];

    NSMutableString * mstr3;

    NSMutableString * mstr4=[[ NSMutableString alloc ] initWithString : @"welcome" ];

 

    NSLog( @"mstr1 addr is %p" ,mstr1);

    NSLog( @"mstr2 addr is %p" ,mstr2);

    NSLog( @"mstr3 addr is %p" ,mstr3);

    NSLog( @"mstr4 addr is %p" ,mstr4);

 

    NSLog( @"mstr1 retainCount is %i" ,[mstr1 retainCount]);

    NSLog( @"mstr2 retainCount is %i" ,[mstr2 retainCount]);

    //NSLog(@"mstr3 retainCount is %i",[mstr3 retainCount]);

 

    mstr3=[mstr1 retain];

    NSLog( @"mstr3=[mstr1 retain];" );

 

    NSLog( @"mstr1 retainCount is %i" ,[mstr1 retainCount]);

    NSLog( @"mstr3 retainCount is %i" ,[mstr3 retainCount]);

    NSLog( @"mstr3 addr is %p" ,mstr3);

 

    mstr3=[mstr2 retain];

    NSLog( @"mstr3=[mstr2 retain];" );

    NSLog( @"mstr2 retainCount is %i" ,[mstr1 retainCount]);

    NSLog( @"mstr3 retainCount is %i" ,[mstr2 retainCount]);

    NSLog( @"mstr3 addr is %p" ,mstr3);

 

    /*

 

     2012-07-14 11:07:36.652 testMem[878:f803] mstr1 addr is 0x68706b0

     2012-07-14 11:07:36.655 testMem[878:f803] mstr2 addr is 0x6876040

     2012-07-14 11:07:36.656 testMem[878:f803] mstr3 addr is 0x2a35

     2012-07-14 11:07:36.657 testMem[878:f803] mstr4 addr is 0x686fbf0

 

     2012-07-14 11:07:36.657 testMem[878:f803] mstr1 retainCount is 1

     2012-07-14 11:07:36.658 testMem[878:f803] mstr2 retainCount is 1

 

     2012-07-14 11:07:36.659 testMem[878:f803] mstr3=[mstr1 retain];

 

     2012-07-14 11:07:36.660 testMem[878:f803] mstr1 retainCount is 2

     2012-07-14 11:07:36.660 testMem[878:f803] mstr3 retainCount is 2

 

     2012-07-14 11:07:36.661 testMem[878:f803] mstr3 addr is 0x68706b0

 

     2012-07-14 11:07:36.662 testMem[878:f803] mstr3=[mstr2 retain];

 

     2012-07-14 11:07:36.663 testMem[878:f803] mstr2 retainCount is 2

     2012-07-14 11:07:36.663 testMem[878:f803] mstr3 retainCount is 2

     2012-07-14 11:07:36.664 testMem[878:f803] mstr3 addr is 0x6876040

 

 

     */

 

 

}

 

self .i_test= self .i_test+ 1 ;

 

}

 

簡而言之,引用計數實際上是指向其記憶體地區的指標數,從記憶體塊的角度去理解,就很容易理解了。


問Objective-c 記憶體溢出問題經驗匯總,那個好心人共用一下

iOS平台的記憶體使用量引用計數的機制,並且引入了半自動釋放機制;這種使用上的多樣性,導致開發人員在記憶體使用量上非常容易出現記憶體流失和記憶體莫名的增 長情況; 本文會介紹iOS平台的記憶體使用量原則與使用陷阱; 深度剖析autorelease機制;低記憶體警示後的處理流程;並結合自身執行個體介紹記憶體暴增的問題追查記錄以及相關工具的使用方式;
iOS平台記憶體常見問題
作為iOS平台的開發人員,是否曾經為記憶體問題而苦惱過?記憶體莫名的持續增長,程式莫名的 crash,難以發現的記憶體流失,這些都是iOS平台記憶體相關的常見問題;本文將會詳細介紹iOS平台的記憶體管理機制,autorelease機制和記憶體 的使用陷阱,這些將會解決iOS平台記憶體上的大部分問題,提高了程式的穩定性;
1 iOS平台記憶體管理介紹
iOS平台的記憶體管理採用引用計數的機制;當建立一個對象時使用alloc或者allWithZone方法時,引用計數就會+1;當釋放對象使用release方法時,引用計數就是-1; 這就意味著每一個對象都會跟蹤有多少其他對象引用它,一旦引用計數為0,該對象的記憶體就會被釋放掉;另外,iOS也提供了一種延時釋放的機制 AutoRelease,以這種方式申請的記憶體,開發人員無需手動釋放,系統會在某一時機釋放該記憶體; 由於iOS平台的這種記憶體管理的多樣性,導致開發人員在記憶體使用量上很容易出現記憶體流失或者程式莫名崩潰的情況,本文會詳細介紹iOS平台記憶體的使用規範與技 巧以及如何利用工具避免或者發現問題;
2 iOS平台記憶體使用量原則
2.1 對象的所有權與銷毀
2.1.1 誰建立,誰釋放;
如果是以alloc,new或者copy,mutableCopy建立的對象,則必須調用release或者autorelease方法釋放記憶體;
如果沒有釋放,則導致記憶體流失!
2.1.2 誰retain,誰釋放;
如果對一個對象發送 retain訊息,其引用計數會+1,則使用完必鬚髮送release或者autorelease方法釋放記憶體或恢複引用計數;
如果沒有釋放,則導致記憶體流失!
2.1.3 沒建立且沒retain,別釋放;
不要釋放那些不是自己alloc或者retain的對象,否則程式會crash;
不要釋放autorelease的對象,否則程式會crash;
2.2 對象的深拷貝與淺拷貝
一般來說,複製一個對象包括建立一個新的執行個體,並以原始對象中的值初始化這個新的執行個體。 複製非指標型執行個體變數的值很簡單,比如布爾,整數和浮點數。複製指 針型執行個體變數有兩種方法。一種方法稱為淺拷貝,即將原始對象的指標值複製到副本中。因此,原始對象和副本共用引用資料。另一種方法稱為深拷貝,即複製指標 所引用的資料,並將其賦給副本的執行個體變數。
2.2.1 深拷貝
深拷貝的流程是 先建立一個新的對象且引用計數為1,並用舊對象的值初始化這個新對象;
ClassA* objA = [[ClassA alloc] init];
ClassA* objB = [objA copy];
objB是一個新對象,引用計數為1,且objB的資料等同objA的資料;
注意: objB需要釋放,否則會引起記憶體流失!
2.2.2 淺拷貝
淺拷貝的流程是,無需引入新的對象,把原有對象的引用計數+1即可
ClassA* objA = [[ClassA alloc] init];
ClassA* objB = [objA retain];
注意: objB需要釋放,恢複objA的引用計數,否則會引起記憶體流失!
2.3對象的存取方法2.3.1 屬性聲明......餘下全文>>
 
ios記憶體管理機制

後台不佔用cpu但是佔用運存,程式開多了會自動關閉一些程式騰出運存
 

聯繫我們

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