在 iOS 中引用計數(shù)是內(nèi)存的管理方式,雖然在 iOS5 版本中,已經(jīng)支持了自動引用計數(shù)管理模式,但理解它的運行方式有助于我們了解程序的運行原理,有助于 debug 程序。
操作系統(tǒng)的內(nèi)存管理分成堆和棧。
在堆中分配的內(nèi)存,都試用引用計數(shù)模式;在棧中則不是。
NSString 定義的對象是保存在棧中,所以它沒有引用計算。看一些書上說它的引用計算會是 fffffffff 最大整數(shù),測試的結(jié)果顯示它是- 1. 對該對象進行 retain 操作,不好改變它的 retainCount 值。
MutableNSString 定義的對象,需要先分配堆中的內(nèi)存空間,再初始化才能使用。它是采用引用計數(shù)管理內(nèi)存的。對該對象做 retainCount 操作則每次增加一個。
其實,引用計數(shù)是對內(nèi)存區(qū)域的空間管理方式,是應從內(nèi)存塊的視角去看的。任何對象都是指向它的指針,有多少個指針指向它,就有多少個引用計算。
如果沒有任何指針指向該內(nèi)存塊了,很明顯,該內(nèi)存塊就沒有對象引用了,引用計算就是 0, 系統(tǒng)會人為該內(nèi)存區(qū)域已經(jīng)空閑,于是立即清理,也就是更新一下管理堆的鏈表中某個標示位。
(miki西游 @mikixiyou 原文 鏈接: http://mikixiyou.VEvb.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 沒有指向任何內(nèi)存區(qū)域。
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]);
/*
結(jié)果如下:
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
在棧中,內(nèi)容相同的對象 str1 和 str4 ,都分配在一個內(nèi)存區(qū)域中,這點是 c 編譯器的功能,有利于內(nèi)存使用和效率。
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 ;
}
簡而言之,引用計數(shù)實際上是指向其內(nèi)存區(qū)域的指針數(shù),從內(nèi)存塊的角度去理解,就很容易理解了。
新聞熱點
疑難解答