『OCプレミアムプログラミング』ノート1-引用カウント&メモリ管理

4141 ワード

前言


最近『Objective-C高度プログラミングiOSとOS Xマルチスレッドとメモリ管理』という本を読んでいます.次に本の第1章はメモリ管理、第2章はblock、第3章はGCDの構造に従って、それに応じて3編のノートを完成しなければなりません.

メモリ管理の考え方


OC内のメモリ管理は「参照カウントメカニズム」で実現される:**各オブジェクトが作成されたばかりのときの参照カウントは1であり、他のオブジェクトに一度持たれている場合は1を加算する.リリースを持っている場合は1を減らし、最後にそのオブジェクトの参照数が0の場合、そのオブジェクトは破棄されます.**しかし、メモリ管理を考える角度を変えて理解することもできます.次のようになります.
**「自分で生成したオブジェクトは、自分で自動的に所有します.」-alloc,new,copy,mutableCopyなどの方法;**「自分で生成しない対象は、自分でも持つことができる」**「自分が所有していないオブジェクトは解放できません.**例えば:1.すでに自分が釈放したばかりの相手は自分でもう持っていないし、もう釈放できない.2.ARC以外の環境では、arrayメソッドはオブジェクトのみを生成しますが、オブジェクト自体は保持されていないため、次のコードは間違いありません.
NSArray *arr =  [NSArray array];
[arr release];

メソッドでオブジェクトを生成し、呼び出し元に戻す場合:1.allocなどの方法で生成される.2.alloc以外の方法で生成する.
  • はalloc等、あるいはalloc等で始まる方法で生成されたオブジェクトはすべて自動的に保有されている.すなわち、参照カウントは1に設定されている(alloc法で返されたオブジェクトは呼び出し者によって所有されている.つまり、呼び出し者はalloc法によってそのオブジェクトを存続させたいという意思を表している).
  • allocメソッドではなくallocメソッドでオブジェクトを生成し、オブジェクトを取得できるが持たない場合はautoreleaseメソッドを使用して自動リリースプールに入れ、pool終了時にpoolとともにrelease(pool dealloc時にその中のすべてのオブジェクトをrelease)
  • alloc/retain/release/deallocなどの方法の実現


    alloc:


    allocメソッドで呼び出されたallocWithZone:メソッドは、メモリ領域に転送されてメモリ領域を生成しますが、メモリNSZoneの問題はほとんど気にしません.基本的にはデフォルトの割り当て方式でオブジェクトのメモリ領域に分けられ、すぐに0に設定されます.
    allocはオブジェクトを作成すると自動的に保持されます.すなわち、参照カウントは1です.
    GNUstepフレームワークでは、オブジェクトのメモリヘッダにオブジェクトの現在の参照カウントを記録する空間(整数)があり、参照カウントを読み出す方法retainCount実装メカニズムは、その小空間にアクセスする整数retainedである.一方、retainはretained++をインクリメントし、releaseはretained--をインクリメントします.retained==0の場合、deallocを呼び出してオブジェクトを破棄します.アップルがオブジェクトを生成する原理はGNUstepとあまり差がないが、参照カウントの管理は異なり、アップルはハッシュテーブルを採用してオブジェクトの参照カウントを管理し、このテーブルのkeyはハッシュ化されたメモリブロックアドレスであり、valueはその参照カウントである.

    autorelease


    自動リリースプール:
    //  ARC 
    
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //  
        id obj = [[NSObject alloc] init]; //  obj
        [obj autorelease]; //  obj 。
        [pool drain]; // pool drain dealloc pool , release( pool release )
    

    **注意:**poolを入れたオブジェクトは、poolが終了するまで統一的に解放されるため、自動解放プールに大量のオブジェクトが入れられると、プログラムメモリが上昇します.
    autoreleaseの実装:使用中の現在存在するpoolオブジェクトを取得し、そのオブジェクトをプールに追加し([pool addObject:obj])、poolメモリにリスト(すなわち配列を保持して挿入されたオブジェクトを記録する)、すなわち[pool addObject:obj]内部実装は、次のようになります.
    - (void)addObject:(id)obj
    {
        [_array addObject:obj];
    }
    

    poolのdrainメソッドは、その配列をループし、すべてのオブジェクトをreleaseしてから、その配列をreleaseします.

    所有権修飾子


    ARCが有効な場合、所有権修飾子がオブジェクトを修飾する必要があります:**何も書かない場合、デフォルトは__strongです.これらの修飾子には、属性を定義する際に使用される「メモリ管理の意味」strong,weakなどが対応しています.**
    __strong,
    __weak,
    __unsafe_unretained,
    __autoreleasing
    

    __strong


    ARC環境では、__strong修飾子はデフォルトの修飾子です.つまり、私たちが書いたコードは所有権修飾子を明確に明記していませんが、デフォルトは__strongです.
    id obj = [[NSObject alloc] init];
    
    //  __strong 
    id __strong obj = [[NSObject alloc] init];
    
    __strongの修飾子は何の役に立つのでしょうか?**__strong修飾子は、オブジェクトに対する「強い参照」を表す.強いリファレンスを持つポインタは、その役割ドメインを超えたときに破棄され、強いリファレンスが消えるにつれてリファレンスのオブジェクトも解放されます.**
        // ARC 
        id __strong obj = [[NSObject alloc] init];
    

    上のコードは次のコードと同じです.
    {   //  ARC 
        id obj = [[NSObject alloc] init];
        
        // .... 
        
        [obj release];
    }
    

    __weak

    __weak修飾子の存在は、「ループリファレンス」の問題を解決するために導入され、弱いリファレンスであり、弱いリファレンスはオブジェクトを持たない.
        id __weak obj1 = nil;
        {
            id __strong obj0 = [[NSObject alloc] init];
            obj1 = obj0;
            NSLog(@" :obj0:%@----obj1:%@",obj0,obj1);
        }
        NSLog(@" :obj1:%@",obj1);
     //  obj0 , , obj1 nil
    
     :obj0:----obj1:
     :obj1:(null)
    

    また、**_Weak修飾オブジェクトは、自動リリースプールautoreleaseに登録されます.**したがって、__weakの大量使用は避けるべきであり、循環参照などの問題を避ける必要がある場合にのみ使用する.__weak修飾のオブジェクトを勝手に定義しないという意味で、__weak修飾のオブジェクトが複数回使用されると、自動解放プールに複数回登録されることを避けることもあります.したがって、メモリのことを考えて、__strong修飾オブジェクトに値を割り当てて、後続の使用のために使用することができます.これにより、自動リリースプールに1回しか登録されません.