2011年3月31日 星期四

iPhone 內存管理(轉)


copy 和retain 的區別

copy: 建立一個索引計數為1的對象,然後釋放舊對象 retain:釋放舊的對象,將舊對象的值賦予輸入對象,再提高輸入對象的索引計數為1 那上面的是什麼該死的意思呢? Copy其實是建立了一個相同的對象,而retain不是: 比如一個NSString對象,地址為0×1111,內容為@”STR” Copy到另外一個NSString之後,地址為0×2222,內容相同,新的對象retain為1,舊有對像沒有變化 retain到另外一個NSString之後,地址相同(建立一個指針,指針拷貝),內容當然相同,這個對象的retain值+1 也就是說,retain是指針拷貝,copy是內容拷貝。 哇,比想像的簡單多了… 誤釋放對象 

問題一: 
value = [array objectAtIndex:n]; 
//得到一個數組中的對象 
[arry removeObjectAtIndex:n]; 

//卸載那個對象 因為value得到了那個對象,但是由於另外一個擁有者release了該對象,所以其實value現在成了搖擺指針(無效數據) 

問題二: myArray = [ NSArray array]; ... [myArray release]; NSArray返回的是一個自動釋放對象,不僅myArray不應該在一段時間後release,而應該在適當的時候先retain,以防止該array被系統誤釋放。 

問題三: rocket = [rocketLauncher aRocket]; [rocketLauncher release]; 和array這種數據收集類對像一樣,如果我們得到了一個類的子對象而不retain它,那麼在原父類被釋放的時候,這個rocket其實也會失去其意義。 Cocoa不同內存管理環境下的autorelease H 混合內存管理環境:垃圾收集法(Garbage Collection)+索引計數法(Reference Counting) 雖然大多數情況下混合環境是不被推薦的,但是如果在這個情況下,autorelease需要注意以下事項: 垃圾收集混合環境下:應該使用drain方法,因為release在GC模式下沒有意義 索引計數環境下:drain和release對於autoreleasepool(自動釋放池)的效果相同 對autorelease的誤解 A Cocoa的內存管理分為索引計數法(Reference Counting/ Retain Count)和垃圾收集法(Garbage Collection)。 而iPhone上目前只支持前者,所以autorelease就成為很多人的“捷徑”。 但是! autorelease其實並不是“自動釋放”,不像垃圾收集法,對對象之間的關係偵測後發現垃圾-刪除。 但是autorelease其實是“延後釋放”,在一個運行週期後被標記為autorelease會被釋放掉。 切記小心使用autorelease,理解autorelease,防止在你還需要該對象的時候已經被系統釋放掉了。 Interface Builder參與的內存管理問題 要點: 如果一個變量在類中被定義為了 ​​IBOutlet 那麼你無需對其進行實例化,xib載入器會對其初始化。 如果一個變量在類中被定義為了 ​​IBOutlet 那麼你必須負責將其釋放。 xib載入器不會幫忙的… … *切不要初始化兩回,內存會溢出,而且對象鎖定也會出錯。 關於索引計數(Reference Counting)的問題 *retain值= 索引計數(Reference Counting) NSArray對象會retain(retain值加一)任何數組中的對象。 當NSArray被卸載(dealloc)的時候,所有數組中的對象會被執行一次釋放(retain值減一)。 不僅僅是NSArray,任何收集類(Collection Classes)都執行類似操作。 例如NSDictionary,甚至UINavigationController。 Alloc/init建立的對象,索引計數為1。 無需將其再次retain。 [ NSArray array]和[ NSDate date]等“方法”建立一個索引計數為1的對象,但是也是一個自動釋放對象。 所以是本地臨時對象,那麼無所謂了。 如果是打算在全Class中使用的變量(iVar),則必須retain它。 缺省的類方法返回值都被執行了“自動釋放”方法。 (*如上中的NSArray) 在類中的卸載方法“dealloc”中,release所有未被平衡的NS對象。 (*所有未被autorelease,而retain值為1的) NSString的內存管理 如下實例: aString = @"I am a string that 2 years old, man!" ; 這種情況下,字符串儲存和管理由系統做,我們不用操心。 aString = [ NSString stringWithFormat: @"I am a string that %d years old, man!" ,2]; 第二種情況下,我們需要去retain和release這個字符串,系統不管。 Objective-C內存管理 1,你初始化(alloc/init)的對象,你需要釋放(release)它。 例如: NSMutableArray aArray = [[ NSArray alloc] init]; 後,需要 [aArray release]; 2,你retain或copy的,你需要釋放它。 例如: [aArray retain] 後,需要 [aArray release]; 3,被傳遞(assign)的對象,你需要斟酌的retain和release。 例如: obj2 = [[obj1 someMethod] autorelease]; 對象2接收對象1的一個自動釋放的值,或傳遞一個基本數據類型(NSInteger,NSString)時: 你或希望將對象2進行retain,以防止它在被使用之前就被自動釋放掉。 但是在retain後,一定要在適當的時候進行釋放。 為什麼不能直接調用dealloc而是release dealloc不等於C中的free,dealloc並不將內存釋放,也不會將索引計數(Reference counting)降低。 於是直接調用dealloc反而無法釋放內存。 在Objective-C中,索引計數是起決定性作用的。

沒有留言:

張貼留言