objective c 内存管理

来源:互联网 发布:剑灵夕颜捏脸数据 编辑:程序博客网 时间:2024/05/23 13:25

Objective-C在管理内存时,遵循一套简单的规则。

每一个对象都有一个名为"retainCount"的变量,它表示该对象有多少个引用。

[java] view plaincopy
  1. class *obj = [class alloc];//alloc会导致retainCount为1  
  2.   
  3. [obj retain];//retainCount++ 通常在对象赋值之后这样做,代表它多了一个引用。  
  4.   
  5. [obj release];//retainCount-- 通常在使用完该对象的时候这样做。  

当 retainCount为0时,运行时环境会通过调用[obj dealloc]来释放对象占用的内存。


下面 看一个例子:

[java] view plaincopy
  1. Test *t1 = [[Test alloc] initWithNum:12];//创建了一个对象,t1是该对象的引用,由于调用了alloc此时retainCount为1  
  2. Test *t2 = t1;//此时t2也要使用该对象  
  3. [t2 retain];//t2要使用对象 就必须要retain,此时retainCount为2  
  4. [t1 release];//t1这时不用该对象了 就release了,也就是放弃了对象的使用权,此时retainCount为1  
  5. [t2 release];//t2使用完了 就release 此时retainCount为0,立刻会调用dealloc来释放内存  
其实,规则很简单。谁使用谁就先retain,用完在release就可以了。这样就不会内存泄露了。


oc中存在一个autorelease pool,其实它是一个NSMutableArray。

把对象加入到autorelease pool:

[java] view plaincopy
  1. [obj autorelease];  
autorelease在释放的时候会给所有的对象发送release,如果该对象的retainCount为1,那么结果导致 retainCount为0,然后运行时就会调用对象的dealloc,以此来实现内存释放。

如果你

[obj retain];

之后没有

[obj release];

在autorelease pool 释放的时候一样会内存泄露!记住autorelease pool只是给对象发送一次release而已!




【iPhone 編程】alloc, retain, release 和 copy 的概念

作為一個從學習 C++,Java 開始的程式員,iPhone 編程所帶來的最大挑戰莫過於reference count 的概念。

剛開始接觸 Objective C,在 XCode 裡摸來摸去,總免不了要跟這傢伙碰面: 

相信我,看見它多數的原因都是 reference count 的概念搞不清楚所引致的。 

首先我們知道,要使用一個 object 的時候,我們必須要給它一個落腳的地方,且我們必須告訴系統說這一塊 memory 是我們擁有的,請不要擅自將在裡頭居住的 object 趕走。這就是我們平時寫 alloc 時所做的事情:

?
1
NSString*exampleString=[[NSStringalloc] init];

分配(allocate)了一塊 memory 後,系統便會自動紀錄此 object 的 retain count 為 “1″。意即:這 object 正被一個名為 “exampleString” 的變數所擁有/聯繫著。若我們的程式某處也想擁有這個 object,我們可以:

?
1
NSString*anotherString=[exampleString retain];

把這個 object 的 retain count 加一(= 2)。這樣做的話,我們就不必擔心若 exampleString有什麼三長兩短,anotherString 也受到牽連。

當然,能夠擁有一個 object,自然也能放棄它。在這裡我們用 “release”。如以上例子,當我們已不再需要 exampleString,我們可以放棄 exampleString 對這個 object 的擁有權:

?
1
[exampleString release];

這樣做便把這 object 的 retain count 減一,變為 1。意思是這 object 還有一個擁有者,那就是 anotherString 了。當我們決定了要完全釋放這個 object(deallocate)時,可以通過release anotherString,把 retain count 變0。這時,系統便會自動清除它了。

當然,如果你沒有適當地 retain,又狂妄地 release object 的時候,就會遇見上面提到的那個傢伙了。會出現 bad access 錯誤的原因就是系統根本找不到你所要釋放的東西。

要弄清除的概念是,

retain 不代表分配了一個新的 memory

筆者便曾經搞錯了這個概念。如果你想要複製一個object,你所需要的指令是 “copy”。

?
1
2
MyObject*originalObject=[[MyObject alloc] init];
MyObject*duplicatedObject=[originalObjectcopy];

以上兩行指令已經分配了兩塊 memory。對其中一個 object 所做的改變,不會影響到另外一個,且他們各自的 retain count 為1。

應該說明的是,由於 object 的性質各有不同,如果有需要用到copy指令,你應該為你的object class 加入 -(id)copyWithZone:(NSZone*)zone 函數。有興趣知道更多的話,可以到這裡參考。



。通常在method中把参数赋给成员变量时需要retain。是为了防止 参数的计数器为0 被销毁了 但是成员变量还在使用这个参数  这样就会出错




一个一直困惑的问题:


-(void) setFirst : (NSString *) f{        [f retain];        [first release];        first = f;}

对于first来说,先release后赋值,是因为如果先赋值,first就指向了f,导致first先前指向的内存无法被访问到,无法释放,造成内存泄露。

先retain再release是为了防止f和first本身指向的是同一个地址,如果直接release,再retain的话会导致该地址引用计数器为0,内存被释放,f和first均成为野指针。
如果不要前两行,直接赋值的话,f可能会被调用这个函数的调用者给释放掉,就导致了first无法在该类实例中继续被使用了,因此赋值的时候要把它的引用计数增加1



其实,下面这种说法更好理解一些:

首先形参f的作用域为setFirst函数内,所以当setFirst函数结束时,f会被释放,而first是在setFirst运行完后用到的(
NSString *first =[[NSString alloc] initWithCString: "Tom"];
),所以此处 retain; 当first已经存在时,就需要先把它释放,再赋值,如果没有释放,会使得原来的数据再也无法访问到,造成内存泄露。


有可能f和first指向同一个地址,直接赋值的话,f可能会被调用这个函数的调用者给释放掉。

原创粉丝点击