Objective-c-memory-management

提供:Dev Guides
移動先:案内検索

Obj-Cメモリ管理

メモリ管理は、プログラミング言語で最も重要なプロセスの1つです。 オブジェクトのメモリが必要なときに割り当てられ、不要になったときに割り当てを解除するプロセスです。

オブジェクトメモリの管理はパフォーマンスの問題です。アプリケーションが不要なオブジェクトを解放しないと、メモリフットプリントが増大し、パフォーマンスが低下します。

Objective-Cのメモリ管理手法は、大きく2つのタイプに分類できます。

  • 「手動保持リリース」またはMRR
  • 「自動参照カウント」またはARC

「手動保持リリース」またはMRR

MRRでは、オブジェクトを独自に追跡することでメモリを明示的に管理します。 これは、FoundationクラスNSObjectがランタイム環境とともに提供する参照カウントと呼ばれるモデルを使用して実装されます。

MRRとARCの唯一の違いは、前者では保持と解放が手動で処理され、後者では自動的に処理されることです。

次の図は、Objective-Cでのメモリ管理の動作例を示しています。

Objective-Cメモリ管理

クラスAオブジェクトのメモリライフサイクルを上の図に示します。 ご覧のとおり、保持カウントはオブジェクトの下に表示されます。オブジェクトの保持カウントが0になると、オブジェクトは完全に解放され、メモリは他のオブジェクトが使用できるように割り当て解除されます。

クラスAオブジェクトは、NSObjectで利用可能なalloc/initメソッドを使用して最初に作成されます。 現在、保持カウントは1になります。

現在、クラスBはクラスAのオブジェクトを保持し、クラスAのオブジェクトの保持カウントは2になります。

次に、クラスCはオブジェクトのコピーを作成します。 これで、インスタンス変数に同じ値を持つクラスAの別のインスタンスとして作成されます。 ここでは、保持カウントは1であり、元のオブジェクトの保持カウントではありません。 これは、図の点線で表されています。

コピーされたオブジェクトは、リリースメソッドを使用してクラスCによってリリースされ、保持カウントが0になるため、オブジェクトは破棄されます。

最初のクラスAオブジェクトの場合、保持カウントは2であり、破棄するために2回解放する必要があります。 これは、保持カウントをそれぞれ1と0に減らすクラスAとクラスBのリリースステートメントによって行われます。 最後に、オブジェクトは破棄されます。

MRR基本ルール

  • 作成するオブジェクトはすべて所有します。名前が「alloc」、「new」、「copy」、または「mutableCopy」で始まるメソッドを使用してオブジェクトを作成します
  • retainを使用してオブジェクトの所有権を取得できます。受信したオブジェクトは通常、受信したメソッド内で有効なままであることが保証され、そのメソッドはオブジェクトを呼び出し側に安全に返すこともできます。 私たちは2つの状況で保持を使用します-
  • アクセサメソッドまたはinitメソッドの実装では、オブジェクトの所有権を取得するために、プロパティ値として保存する必要があります。
  • オブジェクトが他の操作の副作用として無効化されるのを防ぐため。
  • 不要になったら、所有するオブジェクトの所有権を放棄する必要があります。オブジェクトにリリースメッセージまたは自動リリースメッセージを送信して、オブジェクトの所有権を放棄します。 したがって、Cocoaの用語では、オブジェクトの所有権を放棄することは、通常、オブジェクトを「解放する」と呼ばれます。
  • 所有していないオブジェクトの所有権を放棄してはなりません。これは、明示的に述べられた以前のポリシールールの当然の結果です。
#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
   NSLog(@"Hello, World! \n");
}

- (void)dealloc  {
  NSLog(@"Object deallocated");
  [super dealloc];
}

@end

int main() {

  /*my first program in Objective-C*/
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass sampleMethod];

   NSLog(@"Retain Count after initial allocation: %d",
   [sampleClass retainCount]);
   [sampleClass retain];

   NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
   [sampleClass release];
   NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
   [sampleClass release];
   NSLog(@"SampleClass dealloc will be called before this");

  //Should set the object to nil
   sampleClass = nil;
   return 0;
}

上記のプログラムをコンパイルすると、次の出力が得られます。

2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this

「自動参照カウント」またはARC

自動参照カウントまたはARCでは、システムはMRRと同じ参照カウントシステムを使用しますが、コンパイル時に適切なメモリ管理メソッド呼び出しを挿入します。 新しいプロジェクトにはARCを使用することを強くお勧めします。 ARCを使用する場合、状況によっては役立つことがありますが、通常、このドキュメントで説明されている基本的な実装を理解する必要はありません。 ARCの詳細については、https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introductionl [ARCへの移行に関するリリースノート]を参照してください。

前述したように、ARCでは、リリースメソッドを保持する必要はありません。コンパイラによって処理されるためです。 実際、Objective-Cの基本的なプロセスは同じです。 内部的に保持および解放操作を使用するため、開発者はこれらの操作を気にせずにコーディングしやすくなります。これにより、書き込まれるコードの量とメモリリークの可能性の両方が削減されます。

Mac OS-XでMRRとともに使用されるガベージコレクションと呼ばれる別の原則がありましたが、OS-X Mountain Lionでの非推奨以来、MRRとともに議論されていません。 また、iOSオブジェクトにはガベージコレクション機能がありませんでした。 また、ARCでは、OS-Xでもガベージコレクションは使用されません。

簡単なARCの例を次に示します。 これは、ARCをサポートしていないため、オンラインコンパイラでは機能しません。

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
   NSLog(@"Hello, World! \n");
}

- (void)dealloc  {
  NSLog(@"Object deallocated");
}

@end

int main() {
  /*my first program in Objective-C*/
   @autoreleasepool {
      SampleClass *sampleClass = [[SampleClass alloc]init];
      [sampleClass sampleMethod];
      sampleClass = nil;
   }
   return 0;
}

上記のプログラムをコンパイルすると、次の出力が得られます。

2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated