你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS 基本內存管理-引用計數器

iOS 基本內存管理-引用計數器

編輯:IOS開發綜合
1.什麼是內存管理   移動設備的內存極其有限,每個app所能占用的內存是有限制的 當app所占用的內存較多時,系統會發出內存警告,這時得回收一些不需要再使用的內存空間。比如回收一些不需要使用的對象、變量等 管理范圍:任何繼承了NSObject的對象需要去管理內存,但是對於對其他基本數據類型(int、char、float、double、struct、enum等)結構,枚舉等不用去關心內存 復制代碼 - (void)test {     int a = 20;         int b = 10;         Person *person = [[Person alloc] init];          // 方法未退出之前 這三行代碼在內存中如圖 } 復制代碼     一旦test方法執行完畢,意味著局部變量的作用域也失效,那麼棧空間的局部變量系統會自動檢測回收。但是堆空間中動態產生的對象是還沒有被回收。如圖       可以看出即使已經沒有指針指向動態產生的對象了,但還是沒有被回收,因此需要手動管理釋放。釋放的方法是為對象發送一條消息。因此需要調用對象的某個方法來釋放對象。   那麼系統是怎麼知道此時的對象需不需要回收呢?這就涉及到了對象結構中的"引用計數"       2.對象結構   每個OC對象內部都有自己的引用計數器,它是一個整數,表示"對象被引用的次數",即有多少人正在使用這個OC對象 每個OC對象內部會自動設置4個字節的存儲空間來存儲引用計數器     3.引用計數器的作用   當使用alloc、new或者copy創建一個新對象時,新對象的引用計數器默認就是1 當一個對象的引用計數器值為0時,對象占用的內存就會被系統回收。換句話說,如果對象的計數器不為0,那麼在整個程序運行過程,它占用的內存就不可能被回收,除非整個程序已經退出     4.操作對象引用計數器的方法   給對象發送一條retain消息,可以使引用計數器值+1(retain方法返回對象本身)retain方法返回的是id類型,那麼哪個對象調用返回的就是自己 給對象發送一條release消息,可以使引用計數器值-1 可以給對象發送retainCount消息獲得當前的引用計數器值      5.對象的銷毀   當一個對象的引用計數器值為0時,那麼它將被銷毀,其占用的內存被系統回收 當一個對象被銷毀時,系統會自動向對象發送一條dealloc消息 一般會重寫dealloc方法,在這裡釋放相關資源,dealloc就像對象的遺言 一旦重寫了dealloc方法,就必須調用[super dealloc],並且放在最後面調用 不能直接調用dealloc方法 一旦對象被回收了,它占用的內存就不再可用,堅持使用會導致程序崩潰(野指針錯誤)     復制代碼     // alloc方法是給堆中分配內存 init方法和內存無關 此時retainCurrent為1     Person *p = [[Person alloc] init];          // 返回的就是對象本身 retainCurrent為2     [p retain];          // retainCurrent為1     [p release];       // retainCurrent為0 說明Person類對象被回收,那麼對應的在內存中的地址已經不可用了 此時的Person對象稱為“僵屍對象”但是此時p指針還是在指向Person類對象所對應的那塊不可用的地址此時的p指針稱為“野指針”     [p release]; 復制代碼      6.開發中要注意的內存管理   默認情況下,Xcode是不會管理僵屍對象的,即使使用了一塊被釋放的內存也不會報錯。為了方便調試,應該開啟僵屍對象監控。如圖設置:       注意三個概念:   僵屍對象:已經被回收的對象,或者說對象所對應的內存地址已經不可用的對象稱為僵屍對象。僵屍對象不可用   野指針:指向一塊不可用內存地址或者指向僵屍對象的指針稱為野指針。給野指針發送消息會報 EXC_BAD_ACCESS錯誤   空指針:沒有指向任何指針變量稱為空指針,也意味著指針變量所存儲的值為0,nil,NULL 這樣可以避免野指針錯誤的發生   復制代碼 /********************************** Person.h **************************************/ #import <Foundation/Foundation.h>   @interface Person : NSObject   @property int age;   @end     /********************************** Person.m **************************************/ #import "Person.h"   @implementation Person   // 重寫父類NSOjbct的遺言方法 對象在被釋放之前一定會調用dealloc方法   - (void)dealloc {     NSLog(@"對象在釋放之前會執行遺言方法被執行");          [super dealloc]; // 一定要調用 而且必須放在最後面 } @end     /********************************** main.m **************************************/ #import <Foundation/Foundation.h> #import "Person.h"     /*   main方法是一個死循環方法以保證程序能持續運行,除非用戶關閉程序或者是手機沒電,程序才能終止  那麼在main方法裡面的Person對象不就一直存在麼,因此必須在main方法裡面將對象回收  */ int main(int argc, const char * argv[]) {     // alloc方法是給堆中分配內存 init方法和內存無關 此時retainCurrent為1     Person *p = [[Person alloc] init];          // 返回的就是對象本身 retainCurrent為2     [p retain];          // retainCurrent為1     [p release];          /*         retainCurrent為0        說明Person類對象被回收,那麼對應的在內存中的地址已經不可用了         此時的Person對象稱為“僵屍對象”        此時p指針還是在指向Person類對象所對應的那塊不可用的地址,此時p指針稱為“野指針”     */     [p release];               /*         對象已經被回收,千萬別以為再給對象發送一個retain消息對象就可以“起死回生”應該節哀順變         執行retain方法會報錯,此時的p指針已稱為野指針執行代碼回報:野指針錯誤      */          // [p retain];          /*         此時對象已經被回收稱為“僵屍對象了”不可以再訪問屬性         在執行p.age = 10;報錯:         -[Person setAge:]: message sent to deallocated instance  消息發送給了已經被釋放的對象         再次證明“僵屍對象不可以用”      */                    /*          一旦指針成為野指針再繼續向p指針所指的對象發送消息就會報錯:Exc_BAd_ACCESS         說明訪問了一塊壞內存(已經被回收、不可用的內存) “野指針錯誤”          那麼此時在對象回收之後將指針變量清空         那麼棧中的指針變量就不會再指向堆中類對象的內存地址了     */     p = nil;          /*           指針變量內部所存儲的值已被清空,那麼指針已經無指向         再給指針發送任何消息指針會無任何響應,而且也不報錯因為OC中沒有空指針錯誤      */     [p release];     [p release];     [p release];     [p release];          return 0;
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved