Androidの最適化パフォーマンスの最適化のケース(3)ジッタとメモリリーク

序文

この連載:
1、説明の仕方によって簡単に理解するために、技術の実用的な値説明
2、詳細に記述されたソースの追跡、ソース・キャプチャー、構造描画クラスを、詳細に発見プロセスの原理を説明しようとする
3、。 Githubのは、デモプロジェクトを実行することができますが、私は、コードを提供している、より多くのアイデアを提供し、より良いアイデアを、必要に応じてくださいCV
操作4時の注意事項、いくつかのピットを探索する過程で、またはデモで一連の原則を終え
GIFで、5図、最も直感的な業績は、デモを表示します

あなたは詳細が薄すぎると思われる場合は、結論を見てスキップすることができます。
限られた容量は、説明が不適切、歓迎メッセージの批判を見つけなければなりません。

1に接続されているこの記事は、APPカトンの最適化


ボディ概要

  • JVMのメモリ管理の知識
  • ジッタメモリの検出と処理
  • そして、処理メモリリーク検出

テキスト

JVMのメモリ管理の知識

  • LMK(LowMemoryKill)機構
    システムがメモリを使い果たしたときにアンドロイド底は、他のプロセスのメモリのニーズを満たすためにいくつかのプロセスを殺すために、特定の規則によれば、あろう。どのレベルの指標であるので、アプリのメモリフットプリントの最適化、効果的に殺されたアプリのシステムであることの確率を減らすことができ、メモリを消費します。
  • GC STW機構
    GC、ガベージコレクションプロセス、GCスレッドタスクを実行する際に、STW(世界を止める)メカニズムがあるだろう、彼は他のすべてのスレッドが中断されて配置されます。GCは非常に頻繁に呼び出す場合、それはメインスレッドにつながる感があるユーザーを与え、滑らかされていません卡顿
  • メモリー・ジッタ多い原因OOMの
    ラージオブジェクトのメモリを適用する必要がある場合は、メモリジッタがあまりにも頻繁に、頻繁に作成され、破壊された多数のオブジェクトで、その結果、この時点では、連続したメモリ空間を大量に生産することができない、一流、失敗適用することが可能ですOOM内存溢出
  • メモリリークの単語を説明するための
    オブジェクトのライフサイクルを保持するオブジェクトへの強い参照のライフサイクルオブジェクトを回復する必要がある発見のライフサイクル不能漏れと考え、リサイクルさを
  • 到達可能性分析GC回復
  • GCスレッドが算出する到達可能性分析アルゴリズムに従って、オブジェクトが回収されているか否かを判断することができるGcRootから、GcRoot検索ダウン、GcRootオブジェクト全体を直接ガベージコレクションに関連しません。
  • 4つの仮想強い弱い参照
    言わず強いと想像。最も一般的に強いが、特別な治療法はありません(匿名内部クラスが外部クラスへの強い参照を保持します含む)強参照されています。役に立たないファントム参照は、議論されることはありません。
    ソフト参照、ならびにいくつかの使用を定義するが、オブジェクトを持っていない、使用することは、SoftRefrence<T>GCを用いて回収した後、メモリ時制で、修飾SoftRefrence<T>改変ターゲット・システムを利用可能な十分なメモリがある場合、関連ソフト参照を持っていないであろうこれは、再利用されます。不十分な場合は、関連するオブジェクト参照のソフト回復。
    弱参照(WeakRefrence<T>)、限り、弱参照に関連付けられたGCトリガオブジェクトが回収されるように、軟らかい基準数よりも弱いです。
    注意,使用软和弱引用,要判定关联对象是否为空。

ジッタメモリの検出と処理

私たちは、RunAppを指して、私たちは通常、通常、アプリケーションを実行するの発展を使用していますが、、であるprofileApp、アプリ起動して実行した後、別の選択肢がある、あなたは、プロファイルとして以下のウィンドウが表示されます

クリックした後、などのプロファイルの下に表示されます、この図は、ネットワーク、メモリとCPU使用率を表示します

図ジッタのメモリは非常にクリアすると、ECGなどのような:

これは、治療の緊急の必要性におけるジッタの非常に明確なメモリがあることを示しています。

メモリのグラフィックス領域をクリックした後、あなたは、詳細なメモリの変化、およびメモリの割り当てを見ることができます:

ここでピットがあります

あなたはトレンドメモリを滑らかに描画し、その誇張ジッタフィギュアの完全なシミュレーションに表示されないから見れば、何のメモリジッタはそれではないんですが?そうではありません。私たちのGCは、メモリの場合には再利用メモリに使用できなくなりますので、アプリケーションがメモリが比較的小さくなっている取る場合、臨界値GCには触れていなかった、それは表示されません断崖式下跌。だから、これはメモリを振らないで観察したところ、どのようにそれを行うには?

ソリューション
Android携帯電話上で8.0以下、低い位置(それが8.0以上であれば、あなたはメモリレコードの傍受に直接ドラッグ&ドロップすることができます)での録音ボタンがあるでしょう。

しばらくした後、それをクリックし、次にタップする:あなたは、以下のフォームを見つけることができます。

このフォームで、録音時間のこの期間内に作成されたオブジェクト、第二のカラムをクリックし、表しAllocations、ソート、作成された数のオブジェクトの最大数を作成するために見つけます:

クリックすると、最初の文字列をランク付けした後、次に、あなたが右側に表示されます。

そして、あなたは新しいウィンドウが表示され、そのうちの一つをクリックしてください:

これまでのところ、見つけることが、手がかりとして順番にこれを独自のクラスやメソッドパッケージ名を見つけ、私たち自身のコードを決定不当オブジェクトを作成します。创建对象元凶

その後、それぞれのコードの下には、ビジネスの最適化、および念頭に置いて目的の操作を実行します。Doが、余分なものを行うためのコードをさせません我々はオブジェクトの作成不当多数につながったAPIシステムを呼び出した場合、システムのAPIは、オブジェクトを作成するので、これは、それを回避するための他の方法は、このAPIの使用の合理化へのコードのビジネス層から、存在していない理由は、我々は考慮しなければならない、そうではありませんその後、別のシステムまたはカスタムAPIのAPIを検討してください。

私たちは、後の最適化をしたし、その後、プロファイルアプリを実行し、プロセスを繰り返します。ように、メモリの揺れが所望の状態を達成するまで。

概要

最適化メモリジッタ、コアが頻繁に作成したオブジェクトを防ぐためです。共通負例である:サイクルは、コールを多数作成するオブジェクト、オブジェクトのAPIを作成します。最適化の主な手段は、オブジェクトの再利用で、一般的な手段は次のとおりです。そのようなメッセージハンドラ単一のリストプール、グライドのビットマップ・プールとしてオブジェクトプーリング、。


そして、処理メモリリーク検出

クラシックケース:取扱いhandler非同期タスクの方法によって引き起こされるメモリリーク

  • 活動中のすべてのタスクを削除onDestroy
    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);//移除所有任务
    }

  • 静的な内部クラス+アクティビティの弱い参照を使用してマナー
    MyHandler handler = new MyHandler(this);
    private static class MyHandler extends Handler {
        WeakReference<Activity> activityWeakReference;

        MyHandler(Activity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            //在执行任务的时候,判断弱引用所关联的对象是否为空,能在对象已经被回收的情况下,不去执行不必要的任务
            switch (msg.what) {
              case 1:
                if (activityWeakReference.get() != null) {
                    //TODO
                }
            }
        }
    }

ツールの利用

それでもprofileApp、最初のprofileメモリの変化を見ました。

  • Q:メモリリークを決定する方法は?
    A:メモリリークが細かい努力で、完全にのみするメモリプロファイルの変化によって、観察することはできません推測します
    アプリ外で使用可能な最大メモリ、アプリケーションがクラッシュし,,これは最も明白になるまで、例えば、アプリのメモリを開いた後、急騰。
    別の例として、繰り返し開閉1インタフェースのメモリ見つける安定ライン内存稳定之后,内存占用值開閉のそれぞれとを)、このインターフェイス上でリークがあることを示している、改善された、オブジェクトを復元することはできません。

使用前のセクションprofile 大部分がオブジェクトを作成し、メモリジッタの原因を取り戻すために学習され、しかし、まだ唯一のプロファイルを介し、漏洩に関与不能知っている哪个类持有了希望被回收的对象的强引用
ここでは、追加のツールを使用する必要がある、と彼の名前が呼ばれている  Eclipse Mat (自分のBaiduのを)

最初に戻すにはprofile

タップして、その後、タップ、インターフェイスは自動的にジャンプします。

ローカルにファイルを保存するには、[保存]ボタンをクリックしてください。

その後:

しかし、ファイルがマットの上で直接開くことができません。

SDKのディレクトリを見つけるにはhprof-conv.exe

ファイルを変換し、cmdのコマンドを使用して、コマンドは次のとおりです。hprof-conv [源文件名] [目标文件名]
として  hprof-conv 1.hprof 2.hprof キャリッジリターン

その結果2.hprof、オープンなツールの使用は、単にマットをダウンロード:

私達はちょうどヒストグラムボタンに焦点を当てる必要があります、そこに多くの指標がありますが、メモリリークを確認します:

この図は、私たち自身のコードは、オブジェクトを作成するなど、フレームワーク層を含むあなたはこの期間のメモリをダンプするすべてのオブジェクトを、一覧表示されます。

ケースのシミュレーション

私は前述のある古典的な場合、シミュレートされたHandler遅延タスクのリードはActivity、次のようにコアコードは、解放することはできませんが。

私は作成することは非常に一般的な方法を使用してhandlerオブジェクトをタスクに遅延を実行するためにそれを使用しますが、遅延タスクの遅延時間があるIntegerタスクが実行された後も長く、最大、。その後、私が繰り返しこのいずれかのうちActivity、次いで上記の方法に従ってdumpしばらく  hprofした後、  hprof-conv 次いで、変換Matオープン:
結果は次の通りであります:

私は、フィルタ情報をいっぱい:SecondActivity 入力します。

最終的な終了ではSecondActivity後に、メモリがまだ保持18役に立たないオブジェクトを。

これは、我々はそれを18に漏れているということではないでしょうか?

必ずしもそうではありません。

以前は、唯一の不合理強い参照、言及した我々は上記の方法によれば、弱ファントム参照を除外しなければならないので、メモリリークにつながります。
その後、我々は情報をすべて展開]を与えるために拡張することができ、次のインターフェイスを見ることができます:

学びHandler源码の同志は、理解するために見ることになりますhandler不当強参照のチェーンがあるため、メモリリークが発生し
、最終的にコールバックオブジェクトが保持している、上の図を見ることができる  SecondActivityオブジェクトを。

callback タスクの遅延時間は、長すぎる強い参照が中に解放され与えることはありませんので、まだ、実行されていないcallback保持Activity主導Activity解放することはできません。

メモリリークを最適化する方法

あなたはので、もし私たちはただ、ハンドラでメモリリークが発生する不合理な使用を見てきたonDestroyすべてのタスクを削除します。

同じタスクを実行し、HPROFマットを下にダンプ:

GCをトリガした後、SecondActivity数が0になると、メモリリークが解決しました。

もちろん、別のアプローチ、静的な内部クラス+弱い存在です。

PS:静的な内部クラスの内部クラスが外部クラス、GCがトリガーされたときに弱参照、失われたオブジェクトのWeakRefrenceの回復への参照を保持しないようにすることです。

public class SecondActivity extends AppCompatActivity {
    Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        handler.postDelayed(runnable, Integer.MAX_VALUE);//依然是那个延时很久的任务
    }

    Runnable runnable = new MyRunnable(this);

    private static class MyRunnable implements Runnable {// 静态内部类
        WeakReference<Activity> activityWeakReference;//弱引用

        MyRunnable(Activity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void run() {

        }
    }
}

しかし、その後、なしを除外。

ヒント

多くのページがリークのトラブルシューティングを行う必要がある場合は、上記の手順は、実現可能な一方で、しかし、我々は、全体のプロセスは非常に長く不快になります閉じたページを開くには、ポイントを行きます。実際には、解決策があります。

ヒストグラムの前に戻ります:

使用している:あなたが操作をしたい場合、あなたは前と後に指定された各ダンプ操作の前と後のHPROF、その後についてのhprof-CONVに変換され、after_ before_になる、そして、日食マットと同時に両方のファイルを開きますafter_.hprofへの切り替え、ボタンの上の画像をクリックしてください:

それは、あなたが比較したいファイルを選択してみましょうbefore_をクリックし、次に濾過しSecondActivityます。

この実施形態は、処理前に漏れることがあり、コード領域の前調査に漏れることができます。私たちの最適化の作業を簡素化します。

エピローグ

メモリリークとJVMは、私が以前に記載されたポイントに加えて、多くの知識を必要とするジッタを最適化するには、特徴点がたくさんあります。メモリの最適化を行うには、JVMは、確かな知識ベースを必要とします。

前:APPカトンの最適化

 

公開された56元の記事 ウォンの賞賛1 ビュー2918

おすすめ

転載: blog.csdn.net/chuhe1989/article/details/104478266
おすすめ