4

Flexアプリケーションでメモリリークの問題が少し発生しました。質問の短いバージョンは次のとおりです。(AcitonScript 3で)特定のオブジェクトへのすべてのライブ参照を検索する方法はありますか?

私が持っているのは、それぞれの背後にあるプレゼンテーションモデルを含むいくつかのビューです(Swizを使用)。対象のビューはTabNavigatorの子であるため、タブを閉じると、ビューはステージから削除されます。ビューがステージから削除されると、Swizはビュー内のモデル参照をnullに設定します。また、ビューからAllChildren()を削除します。

ただし、アプリケーションをプロファイリングするときに、これを実行してGCを実行すると、ビューもプレゼンテーションモデルも解放されません(ただし、両方が相互の参照をnullに設定します)。ビューで使用されている1つのモデルオブジェクト(ただし、プレゼンターではありません)は解放されているため、完全に壊れているわけではありません。

今日はプロファイリングを始めたばかりなので(最適化が早すぎないことを確信しています)、どこかに何らかの参照が浮かんでいると思いますが、どこにあるのかわかりません。デバッグ機能が非常に役立つでしょう。ターゲットオブジェクトを参照するオブジェクトのリストを参照してください。これは可能ですか?ネイティブではない場合、デバッグ目的で将来のアプリにこれをコーディングするための軽量な方法はありますか?

乾杯。

4

3 に答える 3

11

Flex Builder を使用していると仮定すると、Profiler を試すことができます。私の経験では、プロファイリングのパフォーマンスはあまり良くありませんが、メモリ リークを見つけるのに非常に役立ちました。

これは最も直感的なツールではなく、慣れるまでに時間がかかります (つまり、実際に役立つようになるまで)。しかし、私の意見では、少なくとも基本を学ぶために時間を投資することは報われます。プレイヤーがグローバルに使用しているメモリの量 (System.totalMemory が提供する、非常に大まかで不正確で、誤解を招くことが多い指標) を確認することと、実際に各オブジェクトのインスタンスがいくつ作成されたか、まだいくつあるかを追跡することとの間には、大きな違いがあります。生きていて、それらがどこに割り当てられたのか (したがって、コード内の潜在的なリークを見つけて、黒魔術に頼る代わりに実際に修正することができます)。

FB プロファイラーの適切なチュートリアルを知りませんが、おそらくこれが開始の助けになるでしょう。

まず、プロファイラーを起動します。パフォーマンス プロファイリングのチェックを外し、他のすべてをチェックします (メモリ プロファイリングを有効にし、ライブ メモリ データを監視し、オブジェクト割り当てスタック トレースを生成します)。

プロファイラーが起動すると、アプリ オブジェクトに関する統計がクラス別にグループ化されて表示されます。この時点で、フィルターを微調整することができます。大量のデータが表示され、圧倒されるのは非常に簡単です。今のところ、可能であれば、flash や flex にネイティブなものはすべて無視し、収集する必要があると思われるオブジェクトに集中してください。

最も重要な数字は「累積インスタンス」と「インスタンス」です。1 つ目は、これまでに作成されたインスタンスの総数です。2 つ目は、まだ生きているインスタンスの数です。したがって、適切な出発点は、リークが疑われるビューが作成される状態にアプリを移行することです。"cumulative instances" と "instances" には 1 が表示されます。

次に、このビューをクリーンアップする必要があるポイント (アプリの他の部分に移動するなど) に到達するために必要なことは何でも行い、GC を実行します (プロファイラー UI にそのためのボタンがあります)。重要な点は、アプリの動作を期待に照らしてチェックすることです (それが理にかなっている場合)。ガーバージが収集された環境で自動的にリークを見つけることは、定義上ほぼ不可能です。そうでなければ、漏れはありません。ですから、心に留めておいてください。あなたはあなたの期待に反してテストします。オブジェクトのライフサイクルを知っているのはあなたであり、「この時点でこのオブジェクトは収集されているはずです。収集されていない場合は、何か問題があります」と言うことができます。

ここで、ビューの「インスタンス」カウントが 0 に下がった場合、そこにリークはありません。アプリがリークしていると思われる場合は、適切に破棄されていない可能性のある他のオブジェクトを探してみてください。カウントが 1 のままの場合は、ビューがリークされていることを意味します。ここで、その理由と場所を見つける必要があります。

この時点で、"メモリ スナップショット" (Force GC ボタンの横にあるボタン) を取得する必要があります。スナップショットを開き、グリッドでオブジェクトを見つけてダブルクリックします。これにより、このオブジェクトへの参照を持つすべてのオブジェクトのリストが表示されます。これは実際にはツリーであり、おそらく各項目には多数の後方参照などが含まれているでしょう。これらは、ビューの収集を妨げているオブジェクトです。右側のパネルにも、割り当てトレースが表示されます。これにより、選択したオブジェクトがどのように作成されたかが表示されます (スタック トレースによく似ています)。

そこにはおそらく膨大な数のオブジェクトが表示されます。しかし、あなたの最善の策は、あなたが調べているオブジェクト (あなたの見解) よりもライフサイクルが長いものに集中することです。つまり、ステージ、親ビューなどを探します。ビューに依存するオブジェクトではなく、ビューが依存するオブジェクト (それが理にかなっている場合)。ビューにボタンがあり、それにリスナーを追加した場合、ボタンにはビューへの参照が含まれます。ほとんどの場合、これは問題ではありません。ボタンはビューに依存し、ビューが収集されるとボタンも同様になるためです。つまり、オブジェクトがたくさんあるので、集中力を維持しようとする必要があります。そうしないと、どこにも行きません。この方法はかなりヒューリスティックですが、私の経験ではうまくいきます。

リークの原因を見つけたら、ソースに戻り、それに応じてコードを変更します (コードを変更するだけでなく、少しリファクタリングする必要がある場合もあります)。次に、プロセスを繰り返して、変更によって目的の効果が得られたかどうかを確認します。アプリの大きさや複雑さ、アプリについての知識によっては、しばらく時間がかかる場合があります。しかし、一歩一歩進み、一度に 1 つの問題を見つけて修正すれば、最終的にはリークを取り除くことができます。または、少なくとも最悪でより明白なもの。したがって、少し面倒ですが、それは報われます (そして、余談ですが、ほとんどの場合、この地球上のすべてのイベント ハンドラーに対して弱い参照を使用し、すべてのイベント ハンドラーを無効にすることが時間の無駄であることを最終的に理解できます)。単一変数など; それは啓発的な経験です ;)。

お役に立てれば。

于 2010-06-11T05:13:39.087 に答える
2

Flash GC は、参照カウントとマーク アンド スイープを組み合わせて使用​​するため、循環参照を検出します。オブジェクトグラフに別の参照があるようです。最も一般的な理由は、破棄したいオブジェクトがまだ破棄されていないオブジェクトに登録されているイベント ハンドラーを持っていることです。ハンドラーが常に弱い参照で登録されるようにすることができます。可能であれば、すべての (基本) クラスで addEventListener と removeEventListener をオーバーライドして、登録されているリスナーと、削除されない可能性があるかどうかを確認することもできます。

また、オブジェクトのデストラクタを記述して、UI コンポーネントの場合はグラフィックをクリアしてすべての子を削除し、すべてのオブジェクトの場合はすべてのプロパティへの参照を削除できます。そうすれば、オブジェクトだけが RAM に保持され、多くのメモリを必要としません (20 B 程度の小さなフットプリントに加えて、変数ごとに 4 B (数値の場合は 8))。


グリッツback2dos

于 2010-06-10T14:54:10.913 に答える
0

また、メモリリークを見つけるための便利なヒューリスティック: http://www.tikalk.com/flex/solving-memory-leaks-using-flash-builder-4-profiler

于 2013-05-10T12:15:02.020 に答える