讀古今文學網 > iOS編程基礎:Swift、Xcode和Cocoa入門指南 > 12.1 Cocoa內存管理的原理 >

12.1 Cocoa內存管理的原理

之所以要管理引用類型內存是因為對於引用類型對象的引用只不過是指針而已。被指向的真實對像佔據著內存,當該對像產生時,我們需要為其留出這塊內存;當該對像銷毀時,我們需要顯式清理這塊內存。當對像實例化時,內存被預留出來,不過該如何清理內存,應該什麼時候清理呢?

至少,當一個對像不再有其他對像指向它時,那麼這個對象就應該被銷毀。沒有指針指向的對象是無用的對象;它會佔據著內存,不過沒有其他對象可以引用它。這叫作內存洩漏。很多計算機語言都是通過一種叫作垃圾收集的策略來解決這個問題的。通過週期性地沿著對像鏈進行清理,並銷毀那些沒有指針存在的對象來防止內存洩漏。不過在iOS設備上,垃圾收集是一種代價高昂的策略,其內存非常有限,處理器相對來說也比較慢(可能只有一個核心)。這樣,我們就需要手工管理iOS中的內存,當不再需要某個對象時要能精確地銷毀它。

上面所說的困難之處在於「精確」。對像銷毀不能過早,也不能太遲。多個對象可能都會持有相同對象的指針(引用)。如果對像Manny與Moe都擁有指向對像Jack的指針,並且Manny通過某種方式告訴Jack現在就要銷毀,那麼可憐的Moe就會持有一個什麼都不指向的指針(更糟糕的是指向了垃圾)。如果指針所指向的對象在指針不知情的情況下被銷毀了,那麼這個指針就叫作野指針。如果Moe隨後通過該野指針向它認為還存在的對象發送了消息,那麼應用就會崩潰。

為了防止野指針與內存洩漏的出現,有一種基於數字的手工內存管理策略,這個數字由每個引用類型的對象所維護,叫作其保持計數。原則就是其他對象可以增加或減少一個對象的保持計數,並且其他對像只能做這兩件事情。只要對象的保持計數為正數,那麼對象就會存在。其他對象都無法銷毀另一個對像;相反,當對象的保持計數降為0時,它就會被自動銷毀。

根據該策略,需要讓Jack一直存在的每個對象都應該增加Jack的保持計數,當不需要Jack存在時則需要將其保持計數減1。只要所有對象都能很好地遵循這個策略,那麼手工內存管理的問題就會迎刃而解:

·不會再有任何野指針,因為指向Jack的任何對象都會增加Jack的保持計數,這確保Jack會一直存在。

·不會再有內存洩漏,因為不需要Jack的任何對象都會減少Jack的保持計數,這確保Jack最終會被銷毀(保持計數為0表示不再有對象需要Jack了)。