13

私は自分のアプリケーションのさまざまなビルドでしばらく遊んでいますが、奇妙なことが起こるようです:

私のアプリには 5 MB のアイドル フットプリントがあります。ファイルをアップロードするとき、ファイルのサイズのメモリが予約されます。アップロード後、予約済みメモリを解放する必要があります。現在、ビルドに違いがあります (gc = ガベージ コレクター):

  • 32bit i386 no-GC: すべてのメモリが即座に解放されます。
  • 32 ビット i386 GC: ほとんどすべてのメモリが即座に解放されます。残りはしばらくしてから。
  • 64bit x86_64 no-GC: 最小限のメモリが解放されます。10%くらい
  • 64 ビット x86_64 GC: メモリはまったく解放されません。メモリは何時間も予約されたままになります。(活動月)

私はCLANGでLLVMを使用しています。私は今日ずっと楽器を走らせていて、リーク/ゾンビ/などをチェックしていました。すべてがきれいに見えます。(アプリはかなりシンプルです。)

この動作の説明はありますか?


アップデート:

それはいくつかの奇妙なものです。私はこれに問題を沸騰させました:

20MB のファイルを NSData にロードして解放します。ガベージコレクションを有効にせずにこれを行っています。コードは次のとおりです。

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigshit"];
[bla release];

i386 32 ビット用にビルドすると、20 MB が割り当てられて解放されます。ビルドを 64 ビット x86_64 に切り替えると、リリースは何もしません。20MBは割り当てられたままです。

上の写真 32bit 下の写真 64 http://kttns.org/zguxn

上のアプリが 32 ビット用にビルドされ、下のアプリが 64 ビット用にビルドされていることを除いて、2 つのアプリに違いはありません。GC は実行されていません。(GC を有効にすると、同じ問題が発生します。)


更新 2:

applicationDidFinishLaunching: の上位コードのみを使用して新しいココア アプリをゼロから作成すると、同じ動作が観察されます。64 ビット モードでは、メモリは解放されません。i386 は期待どおりに動作します。

NSData ではなく NSString でも同じ問題が発生します。64 ビット カーネルを起動したときにも表示されます。(起動時は64保持)

OS は 10.6.0

4

3 に答える 3

10

まず、InstrumentのObject Graph機器を使用して、メモリが使用中であると見なされなくなったことを確認します。どこかに保持カウントまたは強力な参照がありません。

使用されなくなった場合は、コレクターが気にするしきい値に達していないという理由だけで、メモリが残っています。

ただし、このステートメント:

64ビットx86_64no-GC:最小限のメモリが解放されます。10%のように

私を警戒させます。具体的には、コードが非GCで動作するように設計されている場合(保持/解放あり)、(a)メモリリークが発生し、CFRetainまたはある種のグローバルキャッシュを使用している場合は、GCに影響を与える可能性があります。 )メモリリークがあるかどうかを判断するために適切なツールを使用していません。

では、メモリリークが発生しているとどのように判断していますか?

更新; アクティビティモニターを使用して、プロセスのRSIZE/VSIZEを監視しています。これは、「私のプロセスは時間の経過とともに成長している」以外に役立つことを実際に教えてくれるものではありません。

ほとんどの場合(私はソースを見ていません)、このコードは次のとおりです。

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigpoop"];

20MBのファイルがmmap()プロセスに組み込まれます。malloc()スタイルの割り当てはまったく含まれていません。代わりに、OSは20MBの連続したアドレス空間をプロセスに渡し、ファイルの内容をそれにマップします。NSDataの内容を読み取ると、ファイルのページフォールトが進行します。

を離すblaと、マッピングが破棄されます。ただし、これは、VMサブシステムがアプリケーションのアドレス空間を20MB削減するという意味ではありません。

つまり、実際のメモリではなく、大量のアドレス空間を焼き尽くしています。プロセスは64ビットであるため、アドレススペースはほぼ無限のリソースであり、アドレスを使用するためのコストはほとんどありません。したがって、OSがこのように実装されている理由です。

つまり、リークはなく、アプリは正常に動作しています。GCかどうかは関係ありません。

これはよくある誤解であり、したがって、質問にスターを付けました。

于 2009-09-05T18:56:18.580 に答える
2

ガベージ コレクターは必ずしもすぐにメモリを解放するとは限りません。

Objective-C のガベージ コレクタの場合、Cocoa のガベージ コレクタ オブジェクトにcollectIfNeededメッセージを送信して、今が何らかの収集を行うのに適した時期である可能性があることを示唆するcollectExhaustivelyか、すべてのガベージの収集をすぐに開始するように命令することができます (ただし、これでさえも)中断可能です)。ドキュメントを参照してください。

于 2009-09-05T16:10:28.673 に答える
0

私は iPhoneOS 3.2 で非常によく似た問題を抱えていますが、実際にはメモリが再利用されているとは思いません。最終的にはメモリの警告が表示されます。自分の間違いを見落としている可能性がわずかにありますが、非常に徹底しています。

NSKeyedUnarchiver の unarchiveObjectWithFile: を使用して、1 つの大きな NSData と別のはるかに小さなオブジェクトを含むカスタム オブジェクトを読み込みます。カスタム オブジェクトの dealloc メソッドが呼び出され、NSData オブジェクトが解放され、retainCount == 1 になります。NSData サイズの一部は言うまでもなく、物理メモリは少しも減少せず、繰り返しメモリ警告が確実に生成されます。実際にレベル 2 の警告を受け取るまでテストを行いました。=(

発売前:

(gdb) p (int) [(NSData *) pastItsWelcomeDataのretainCount]
$1 = 1

リリース後:

(gdb) p (int) [(NSData *) pastItsWelcomeData preserveCount]
ターゲットは、このメッセージ セレクターに応答しません。

于 2010-04-29T09:09:19.937 に答える