2013-06-20 10 views
8

私は今までどおりメモリフットプリントを除いて正常に動作すると思われるアプリケーションObjective-Cを書いています。私はXcode 4.6.2の最後のバージョンでARCを使用しています。私のシステムは10.7.5です。ARCは[NSDate date]を使用してもメモリを解放しませんが、[[NSDate alloc] init]を使用して正常に動作します。

私は非常にObjective-Cに新しく、何が私の記憶で起こっているのかを理解する助けが必要です。私は次の基本的なコードがなぜ動作するのかを説明する問題を絞りました。

このコードは、Xcodeが提供するバニラのCocoaベースのアプリケーションテンプレート(ARCが有効)に追加されています。

ケース

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{ 
    NSDate* d; 
    for(int i=0; i<1000000; i++){ 
     d = [[NSDate alloc] init]; 
    } 
} 

すべてが期待どおりになると、ARCはその場でメモリを再利用。すなわち、メモリ使用履歴は非常に平坦です。 forループが終了すると、アプリは約25MBのメモリを消費します。

ケースB

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{ 
    NSDate* d; 
    for(int i=0; i<1000000; i++){ 
     d = [NSDate date]; 
    } 
} 

ここでは、物事は私にはとても神秘的です。アプリを実行するだけで、(実際の)メモリ使用量は約53MBまで増加し続け、永遠にそこにとどまります。

しかし、allocationsプロファイラツールを実行すると、forループの最後に、すべてのオブジェクトの割り当てが解除されることがわかります。これは、オートリリースプールの場合と非常によく似ています。また、forループの本体を@autoreleasepool {}で囲むと、ケースBはケースAのように振る舞います(期待通り)。

ので、3つの質問:

  1. の下ARC、 "自動解放" [NSDate date]とのalloc初期化オブジェクトを使用しての違いは何ですか? (私はここに他の質問に近いものはないと思っていました)
  2. コードを実行するときにARCが起動しないのはなぜですか?
  3. なぜプロファイルアプリケーションと実際のアプリケーションのメモリ動作に違いがありますか?
+0

A:ARCは手動で作成されていることを知っており、 'for'が終了すると解放する必要があります。 B:イベントループ終了時に「autorelease」に入っています。 –

+0

これも私の理解ですが、 "イベントループの終わり"は決して来ないようです!私がどれくらい待っているかにかかわらず、GUIをどのくらい使っているかに関係なく、メモリー使用量は効果的に高く保たれます。チェックする場合はローカルループを作成してチェックしたい場合は – akant

+0

を入力してください。 –

答えて

2

[NSDate date]は、次回プログラムがイベントループに入ったときにリリースされる自動リリースオブジェクトを作成しています。

もう1つのケースは、ARCによってループ内で解放されます。

このようなことを本当に行いたい場合は、独自の自動リリースプールを作成して定期的に排水することができます。 alloc/init場合にはそれらは、すぐに彼らはもう慣れていないとしてリリースされているのに対し、Objective-C: Why is autorelease (@autoreleasepool) still needed with ARC?

+0

はい、これは確かにドキュメントに記載されています。しかし、私は "プログラムがイベントループに入る"という意味には非常に不明です。私はプログラムが再びイベントループに入ることはないと結論づけなければなりませんか?また、プロファイリングや実行中の動作の不一致も説明していません。 – akant

+1

@akant:プロファイリングでは、最適化フラグとともに「リリース」構成を使用します。コンパイラは、不要なretain/autorelease呼び出しを認識して削除します。それは違いを説明するはずです。 –

+1

プログラムはタッチに応答するためにイベントループを入力する必要があります.GUIなどを再描画する必要があります。あなたはメモリ使用量が高く保たれていると言っています - これをどのように測定しましたか?空きのヒープスペースがあったかもしれませんが、そのスペースはカーネルに返されなかったので、そのプロセスに割り当てられたメモリはまだまだ高かったです。 – Bryan

4

自動解放オブジェクトが最終的に解放されている例を参照してください。

この動作は、あなたのオブジェクトは、あなたalloc/initその場合、release方法がループ本体内を送っているのに対し、彼らは、後に解放されるために自動解放されている場合には、ループ全体のためにメモリ内に存続させます。あなたは簡単に@autoreleasepoolでそれをラップすることにより、身体のループメモリ効率を作ることができ

などは、次のとおりです。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{ 
    @autoreleasepool { 
     NSDate* d; 
     for(int i=0; i<1000000; i++){ 
      d = [NSDate date]; 
     } 
    } 
} 

これはあなたがで自動解放プールを作成し、リリースしたいことを知らせる、ARCにヒントを与えるだろうすべてのループ反復。

最も簡単なオプションは、コンパイラが自動的に適切な処理を行うために、alloc/initのメソッドを使用することですが、自動解放されたインスタンスを返すファクトリメソッドが多数あるループ本体がある場合、 @autoreleasepoolブロックはおそらく良い方法です。

最終的に、@autoreleasepoolはARC専用ではありません。以前はLLVM 3.0以来存在していましたが、十分な近代的な目標(すなわち、iOS5とOSX 10.7)では、旧式のNSAutoreleasePoolよりはるかに高速であることが知られています。

+0

良い答え、私の問題を解決しました。私の髪を引っ張っていた。 – Ternary

関連する問題