『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以外の方法で生成する.
OC内のメモリ管理は「参照カウントメカニズム」で実現される:**各オブジェクトが作成されたばかりのときの参照カウントは1であり、他のオブジェクトに一度持たれている場合は1を加算する.リリースを持っている場合は1を減らし、最後にそのオブジェクトの参照数が0の場合、そのオブジェクトは破棄されます.**しかし、メモリ管理を考える角度を変えて理解することもできます.次のようになります.
**「自分で生成したオブジェクトは、自分で自動的に所有します.」-alloc,new,copy,mutableCopyなどの方法;**「自分で生成しない対象は、自分でも持つことができる」**「自分が所有していないオブジェクトは解放できません.**例えば:1.すでに自分が釈放したばかりの相手は自分でもう持っていないし、もう釈放できない.2.ARC以外の環境では、arrayメソッドはオブジェクトのみを生成しますが、オブジェクト自体は保持されていないため、次のコードは間違いありません.
NSArray *arr = [NSArray array];
[arr release];
メソッドでオブジェクトを生成し、呼び出し元に戻す場合:1.allocなどの方法で生成される.2.alloc以外の方法で生成する.
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回しか登録されません.
// ARC
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //
id obj = [[NSObject alloc] init]; // obj
[obj autorelease]; // obj 。
[pool drain]; // pool drain dealloc pool , release( pool release )
- (void)addObject:(id)obj
{
[_array addObject:obj];
}
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回しか登録されません.