Android パフォーマンスの最適化 -- メモリ最適化分析の概要

1. メモリ最適化の概念

1.1 なぜメモリを最適化する必要があるのですか?

メモリの最適化は常に非常に重要な点ですが、注目が不足しています。プログラムの実行にとって最も重要なリソースの 1 つとして、メモリは実行プロセス中に合理的に割り当てられ、リサイクルされる必要があります。不当なメモリ使用量は、ユーザーのアプリケーションの実行を引き起こす可能性もあります。 、ANR、黒い画面により、ユーザー アプリケーションで OOM (メモリ不足) クラッシュが発生する場合もあります。注意深く観察してみると、記憶の問題は比較的複雑であるため、記憶の問題が発生する場所は単なる症状であり、根深い原因ではないことがわかるかもしれません。問題が発生しているコードが爆発したため、開発者はアプリケーションのメモリの問題にさらに注意を払う必要があります。

1.2 記憶障害の症状

  • メモリジッター: ギザギザ、頻繁な GC により遅延が発生する

  • メモリ リーク: 使用可能なメモリが徐々に減少し、GC が頻繁に発生します。

  • メモリ オーバーフロー: OOM、プログラム例外

2. 一般的に使用されるメモリ分析ツール

メモリの問題を解決するには、メモリの問題をより迅速かつ便利に特定できる強力なメモリ分析ツールが必要です。現在主流のメモリ分析ツールには、主に LeakCanary、Memory Profiler、MAT があります。

2.1 リークカナリア

LeakCanary は Square のオープンソース メモリ リーク監視フレームワークで、アプリケーションの実行中に発生するメモリ リークは LeakCanary によって監視および記録されます。

 LeakCanary のメモリ リーク トレース分析では、主に Leaking: NO から Leaking: YES までのトレースを確認すると、TextView が破棄された Activity のコンテキストを保持しているため、メモリ リークが発生していることがわかります。

より具体的なトレース分析については、公式ドキュメント「メモリ リークの修正」を参照してください。

LeakCanary の使用は非常に便利ですが、いくつかの欠点もあります。

  • 依存関係によって使用される LeakCanary の直接参照は、通常、オフライン デバッグに使用され、アプリケーションがオンラインでリリースされるときに閉じる必要があります。

  • アプリケーションのデバッグで遅延が発生する場合がある

したがって、一般的に LeakCanary を使用することは、メモリ リークを特定するための簡単な方法にすぎません。ただし、メモリ ジッターの特定やビットマップの最適化など、より優れたメモリの最適化が必要な場合は、依然として他の分析ツールが必要です。主によく使用されるのはメモリです。プロファイラーとMAT。

2.2 ネイティブサイズ、シャローサイズ、保持サイズ、深さ

後でメモリ プロファイラと MAT について説明するときに、Shallow Size と Retained Size というさらに重要な指標がよく登場します。ネイティブ サイズと深さもメモリ プロファイラーで提供されます。

ヒープ ダンプを取得すると、Memory Profiler にクラスのリストが表示されます。各クラスの「割り当て」列にはインスタンスの数が表示されます。その右側には、ネイティブ サイズ、シャロー サイズ、保持サイズがあります。

次の図を使用して、特定のヒープ ダンプによって記録されたアプリケーション メモリの状態を表します。赤いノードに注目してください。この例では、このノードによって表されるオブジェクトはプロジェクトのネイティブ オブジェクトを参照しています。この状況はあまり一般的ではありませんが、Android 8.0 以降では、ビットマップのピクセル情報が原因でビットマップを使用するときにこのような状況が発生する可能性があります。 JVM のメモリ負荷を軽減するために、ネイティブ メモリに保存されます。

浅いサイズから始めましょう。このデータ列は実際には非常に単純で、オブジェクト自体によって消費されるメモリ サイズです。

Depth は GC Root からこのインスタンスまでの最短パスであり、図中の数字は各オブジェクトの深さ (Depth) です。

オブジェクトが GC ルートに近づくほど、複数のパスを介して GC ルートに接続される可能性が高く、ガベージ コレクション中にオブジェクトが保存される可能性が高くなります。

赤いノードを例にとると、その左側からの参照が破壊されると、赤いノードはアクセスできなくなり、ガベージ コレクションされます。右側の青いノードでガベージ コレクションを実行したい場合は、左右のパスを破棄する必要があります。

Depth 1 のインスタンスが表示された場合、それは GC ルートによって直接参照されていることを意味し、自動的にリサイクルされないことも意味することに注意してください。

以下は、LocationListener インターフェイスを実装するサンプル アクティビティです。コードの強調表示されている部分 requestLocationUpdates() は、現在のアクティビティ インスタンスを使用して locationManager を登録します。ログアウトを忘れると、このアクティビティが漏洩します。ロケーション マネージャーは GC ルートであり、常に存在するため、メモリ内に永久に残ります。

これはメモリ プロファイラで確認できます。インスタンスをクリックすると、メモリ プロファイラーによって、インスタンスを参照しているユーザーを示すパネルが開きます。

Location Manager の mListener がこのアクティビティを参照していることがわかります。参照パネルからヒープの参照ビューに移動すると、さらに一歩進むことができます。これにより、参照のチェーンが期待どおりであることを確認でき、コードにリークがあるかどうか、またどこにリークがあるかを理解するのにも役立ちます。

2.3 メモリプロファイラー

Memory Profiler は、リアルタイムのメモリ状態を表示するために Android Studio に組み込まれているメモリ分析ツールです。

2.3.1 メモリ プロファイラ インターフェイスの説明

公式ドキュメント: メモリ プロファイラを使用して Java ヒープとメモリ割り当てを表示する

2.3.2 メモリジッターを見つけるためのメモリプロファイラー

メモリ ジッターの検出は比較的簡単で、メモリが短期間で上下に変動し、頻繁に GC リサイクルが引き起こされるため、実行中のプログラムがメモリ プロファイラに表示されます。

メモリジッターが発生する一般的な場所:

  • カスタム ビューの onMeasure()、onLayout()、onDraw() は、新しいオブジェクトを使用してオブジェクトを直接作成します。

  • RecyclerView の onBindViewHolder() などのリストは、新しいオブジェクトを使用してオブジェクトを直接作成します。

  • ループを使用したコード内でのオブジェクトの作成

単純なケースを使用してメモリ スラッシングをシミュレートします。

publicclassMainActivityextendsAppCompatActivity {
​@SuppressWarnings("HandlerLeak")privateHandler mHandler = newHandler() {@OverridepublicvoidhandleMessage(Message msg) {// 模拟内存抖动for (int i = 0; i < 100; i++) {String[] args = newString[100000];}
​mHandler.sendEmptyMessageDelayed(0, 30);}};
​@OverrideprotectedvoidonCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);
​findViewById(R.id.button).setOnClickListener(newView.OnClickListener() {@OverridepublicvoidonClick(View v) {mHandler.sendEmptyMessage(0);}});}
}
复制代码

ケースは非常に単純です。つまり、ボタンをクリックするとオブジェクトが頻繁に作成されます。上記のプログラムを実マシン上で実行すると、ギザギザのメモリ変動が発生することはありませんが、以下に示すように、非常に頻繁に GC リサイクルが発生します。

では、メモリジッターが発生する場所を具体的に特定するにはどうすればよいでしょうか?

上記の手順に従います。

  • 位置①: プログラムの実行中に、[記録] ボタンをクリックしてメモリの状態を記録し、[停止] をクリックして記録を停止すると、上の図が表示されます。

  • 位置②: [割り当て] をクリックすると、割り当てられたオブジェクトの数を大きいものから小さいものへの降順、または小さいものから大きいものへの昇順で表示できます。通常は、最大数のオブジェクトを大きいものから小さいものの降順に表示することを選択します。上の図でオブジェクトの数が最も多いのは String オブジェクトです

  • 位置③: インスタンスビューで String オブジェクトを選択すると、以下の Allocation Call Stack が表示され、このオブジェクトのコールスタックの場所が表示されます。

  • 位置④: 割り当て呼び出しスタックから、MainActivity の 18 行目の handleMessage() で String オブジェクトが作成されていることがわかり、メモリ ジッターの場所が特定されます。

上記の操作にはいくつかのヒントがあります。

  • 位置①で操作する前に、干渉を排除するために、変更されたメモリは通常、記録前に手動で GC されます。Android 8.0 以降のデバイスでは、メモリ プロファイラをリアルタイムでドラッグして、表示するメモリ変動範囲を選択できます。

  • 立場② 上記の例は「クラスごとに配置」を直接表示する例ですが、実際のプロジェクトでは「パッケージごとに配置」を選択して、自分のプロジェクトのパッケージ名でクラスを表示する人が多くなります。

2.3.3 メモリ リークを見つけるためのメモリ プロファイラ

前述したように、メモリ リークが発生すると利用可能なメモリが減り続け、システムがメモリを必要とするときにメモリが不足すると GC が発生するため、メモリ ジッターが発生します。

メモリ リークが発生すると、メモリ プロファイラははしご状のメモリ増加傾向を示し、メモリは減少しません。

上の図のメモリ リークは非常に明白ですが、実際のプロジェクト開発でメモリ リークが発生した場合、メモリ リークはそれほど顕著ではなく、実行に時間がかかるとメモリが徐々に増加していることがわかります。現時点では、ダンプ ヒープを見つけやすくする必要があります。

次に、Handler のメモリ リークを例に、Memory Profiler を使用してメモリ リークを分析する方法を簡単に説明します。

public classHandlerLeakActivityextendsAppCompatActivity{private static finalStringTAG = HandlerLeakActivity.class.getSimpleName();
​privateHandler handler = newHandler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 0) {Log.i(TAG, "handler receive msg");}}};
​@Overrideprotected void onCreate(@NullableBundle savedInstanceState) {super.onCreate(savedInstanceState);handler.sendEmptyMessageDelayed(0, 10 * 1000);}
}
复制代码

上記のコードは非常にシンプルで、アプリ起動後、HandlerLeakActivityに入るたびに、Handlerを使ってメッセージの送信を10秒間遅らせ、10秒以内にインターフェースを終了し、この操作を繰り返します。

1. メモリ リークを引き起こす可能性のある操作を複数回繰り返し、メモリ プロファイラ ヒープによって hprof ファイルがダンプされます (操作前に GC による干渉を排除することをお勧めします)。

2. Memory Profiler でヒープ ダンプ ファイル hprof を表示します。

手動 GC の後、Allocations に 5 HandlerLeakActivities が表示され、ヒープ ダンプのインスタンス ビューの下に複数のアクティビティ インスタンスがまだ表示されていることがわかります。これは、メモリ リークが発生したことを示しています。特定のメモリ リークの場所は、リークされたインスタンス クラス オブジェクトでクリックできます。インスタンス ビュー。インスタンス ビューの下の参照には、特定の参照チェーンが表示されます。

新しいバージョンのメモリ プロファイラでは、[アクティビティ/フラグメント リーク] チェックボックスが提供されており、これを選択すると、メモリ リークの可能性がある場所を直接見つけることができます。

2.4マット

2.4.1 MAT の概要

  • メモリ リークとメモリ使用量を検出する強力な Java ヒープ分析ツール

  • 全体的なレポートの生成、問題の分析など

  • 徹底したオフライン利用

公式 Web サイトのダウンロード アドレス: www.eclipse.org/mat/downloa... 、このアドレスによく知っている単語はありますか? そうです、MAT は Eclipse のプラグインです。開発プロセスまたは Android Studio を使用しているため、Eclipse をダウンロードしたくない場合は、MAT の独立したバージョンをダウンロードできます. 解凍後、その中に MemoryAnalyzer.exe の実行ファイルがありますので、それをクリックすることで使用できます。

多くの場合、このツールを Android Studio のヒープ ダンプ機能と組み合わせて使用​​する必要があります。ただし、AS3.0 以降に生成された hprof ファイルは標準の hprof ファイルではないことに注意してください。変換するにはコマンドを使用する必要があります。 : hprof-conv 元のファイルパス変換後のファイルパス

2.4.2 MAT の使い方の概要

①. 概要:概要情報

上位の消費者

  • より多くのメモリを占有するオブジェクトがグラフで表示されます。この列は、メモリ使用量を削減する場合にさらに役立ちます。

  • 最大のオブジェクト: 比較的詳細な情報

漏洩容疑者

  • メモリリークの疑わしい箇所を素早くチェック

②、ヒストグラム:ヒストグラム

  • クラス名: 特定のクラスを具体的に検索します

  • オブジェクト: 特定のクラスのインスタンスがいくつあるか

  • 浅いヒープ: 1 つのインスタンスが占有するメモリの量はどれくらいですか?

  • 保持ヒープ: この参照チェーン上でこれらのオブジェクトが合計でどれくらいのメモリを占有しますか?

Group by package: クラスオブジェクトをパッケージ名の形式で表示します。

リストオブジェクト

  • 発信参照の場合: どのクラスがそれ自体で参照されますか?

  • 受信参照の場合: どのクラス自体が参照されているか

③、ドミネーターツリー

  • 各オブジェクトの支配ツリー

  • パーセンテージ: すべてのオブジェクトのパーセンテージ

アイテムを右クリックすると、リスト オブジェクトも表示されます。ヒストグラムとの違いは何ですか? 主な違いは以下の2点です。

  • ヒストグラム: クラスベースの視点分析

  • dominator_tree: 例に基づく視点分析

④、OQL: オブジェクトクエリ言語。データベースからコンテンツを取得するのと似ています。

⑤、thread_overview: スレッド情報の詳細表示。メモリ内に現在いくつのスレッドが存在するかがわかります。

3. 実用的なメモリジッターソリューション

3.1 メモリジッターの概要

  • 定義: メモリの割り当てと回復が頻繁に行われると、メモリが不安定になります。

  • パフォーマンス: 頻繁な GC、ぎざぎざのメモリ曲線

  • 危険性: 遅延を引き起こし、深刻な場合には OOM を引き起こします。

3.2 メモリジッターが OOM を引き起こす

  • オブジェクトが頻繁に作成されるため、メモリ不足と断片化 (不連続性) が発生します。

  • 不連続なメモリ スライスを割り当てることができないため、OOM が発生します。

3.3 実践的な分析

このパートでは、メモリ ジッターをシミュレートし、プロファイラーを通じてメモリの状況を分析し、特定のメモリ ジッター コードを特定します。

まず、レイアウト ファイル activity_memory.xml を作成しましょう。このファイルには、メモリ ジッターをシミュレートするコードの部分をトリガーするボタンが含まれています。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/btn_memory"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="模拟内存抖动"/>
</LinearLayout>
复制代码

次にMemoryShakeActivityページを定義し、先ほどのレイアウトを読み込み、そのページ内にHandlerを定義し、メモリシェイクをシミュレートするボタンをクリックすると定期的にhandleMessage内のシェイクをシミュレートするコードを実行するというコード全体がわかりやすいです。 :

/*** 说明:模拟内存抖动页面*/publicclassMemoryShakeActivityextendsAppCompatActivityimplementsView.OnClickListener {@SuppressLint("HandlerLeak")privatestaticHandler mHandler = newHandler(){@OverridepublicvoidhandleMessage(@NonNull Message msg) {super.handleMessage(msg);//模拟内存抖动的场景,每隔10毫秒执行一次,循环执行100次,每次通过new分配大内存for (int i=0;i<100;i++){String[] obj = newString[100000];}mHandler.sendEmptyMessageDelayed(0,10);}};@OverrideprotectedvoidonCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_memory);findViewById(R.id.btn_memory).setOnClickListener(this);}@OverridepublicvoidonClick(View view) {if (view.getId() == R.id.btn_memory){mHandler.sendEmptyMessage(0);}}@OverrideprotectedvoidonDestroy() {super.onDestroy();mHandler.removeCallbacksAndMessages(null);}
}
复制代码

それから走り始めて、みんなに見てもらえるように 2 枚の写真を撮りました。最初の写真はジッターをシミュレートするコードが実行される前で、2 番目の写真は実行後です。

上の 2 つの画像から、最初のメモリ画像は比較的安定していることがはっきりとわかりますが、2 番目のメモリ画像はギザギザがあり、突然頻繁に GC が発生します。下に小さなゴミ箱がたくさん見えますか? このとき、メモリ ジッタの現象が現れるのは、メモリ ジッタの特性により一致しているためです。パネル上で一定の距離をドラッグすると、この期間のメモリ割り当てが表示されます。

まず、[Allocations] をダブルクリックし、この列を最大から最小の順に並べると、非常に多くの String 配列があり、最も多くのメモリ サイズを占有していることがわかります (注目に値する点を でマークしました)。長方形) , 現時点ではこのターゲットをロックする必要があります。なぜ String 型の配列がこれほどたくさんあるのでしょうか? おそらくここに問題があります。次に、この問題の原因をトラブルシューティングします。String[] 行をクリックし、右側の [インスタンス ビュー] パネルの任意の行をクリックするのは非常に簡単です。対応するスタック情報が、下の [割り当て呼び出しスタック] パネルに表示されます。どのクラスのどの行についても、右クリックで「jupm to source」を選択すると、指定したソースコードの位置にジャンプすることで、メモリジッターが発生している箇所を特定し、コードを解析したり、解析したりすることができます。対応する変更を加えます。

プロセスの概要:

  1. メモリ プロファイラを使用した予備的なトラブルシューティング。

  1. メモリ プロファイラまたは CPU プロファイラを使用してコードのトラブルシューティングを行う

メモリジッターを解決するためのヒント: ループまたは頻繁な呼び出しを見つける

4. 実際のメモリリーク解決策

4.1 メモリリークの概要

定義: メモリ内に有用なオブジェクトがなくなりました

パフォーマンス: メモリのジッター、使用可能なメモリが徐々に減少します

危険: メモリ不足、頻繁な GC、OOM

4.2 実践的な分析

ここでは、コードはメモリ リーク シナリオをシミュレートするために使用されています。一般的な APP プログラムの場合、多くの場合、最大の問題はビットマップです。ビットマップは大量のメモリを消費するため、シミュレートするとそれがより明らかになります。まず、ImageView コントロールを含むレイアウト ファイル activity_memoryleak.xml を見てみましょう。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/iv_memoryleak"android:layout_width="50dp"android:layout_height="50dp" />
</LinearLayout>
复制代码

次に、特定のビジネスの処理をシミュレートする Callback コールバック インターフェイスと、これらのコールバック インターフェイスを均一に管理する Manager クラスを定義します。

//模拟回调处理某些业务场景publicinterfaceCallBack {voiddpOperate();
}//统一管理CallbackpublicclassCallBackManager {publicstatic ArrayList<CallBack> sCallBacks = new ArrayList<>();publicstaticvoidaddCallBack(CallBack callBack) {sCallBacks.add(callBack);}publicstaticvoidremoveCallBack(CallBack callBack) {sCallBacks.remove(callBack);}
}
复制代码

次に、シミュレートされたメモリ リーク ページにビットマップを設定し、コールバック リスナーを設定します。

/*** 说明:模拟内存泄露页面*/
public classMemoryLeakActivityextendsAppCompatActivityimplementsCallBack{@Overrideprotected void onCreate(@NullableBundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_memoryleak);ImageView imageView = findViewById(R.id.iv_memoryleak);Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.big_bg);imageView.setImageBitmap(bitmap);CallBackManager.addCallBack(this);}@Overridepublic void dpOperate() {}
}
复制代码

OK、コードは完成しました。実際に実行して、このページを数回続けて開いたり閉じたりして、このコードがメモリ リークを引き起こすかどうかを確認してみましょう。

これはプロファイラーを使用してキャプチャしたメモリの画像です。ページを繰り返し切り替えた後、メモリ全体に所々小さなジッターがあることがわかります。ただし、メモリ全体は梯子状に上昇し、使用可能なメモリは徐々に減少します。基本的に、このインターフェイスにメモリ リークがあると結論付けることができます。プロファイラー ツールは、最初はメモリ リークが発生したかどうかを判断するのに役立ちますが、メモリ リークがどこで発生したかを判断することはできません。つまり、コードのどこを変更すればよいかまだわからないため、強力な Java ヒープ ツールを使用する必要があります。この際、MAT を招待してください。

まず、プロファイラーの [Java ヒープのダンプ] ボタンをクリックし、ヒープ ダンプ機能を使用してファイルに変換し、次に [保存] ボタンをクリックしてファイルをローカル ディレクトリに保存する必要があります。たとえば、ここでは次のように保存します。 H ディスク内の Memoryleak.hprof ファイルを保存し、hprof を使用します。 -conv コマンドは、それを標準の hprof ファイルに変換します。ここでの変換名は、次に示すように、memoryleak_transed.hprof になります。

次に、MAT ツールを開いて、生成された変換済みファイルをインポートします。

[ヒストグラム] をクリックして、メモリ内に残っているすべてのオブジェクトを表示します。次に、クラス名に内容を入力して、探したいオブジェクトを検索できます。

次に、オブジェクトの特定の情報、占有数とメモリ サイズが表示され、実際にはメモリ内に 6 つの MemoryLeakActivity オブジェクトがあることがわかりました。

次に、[オブジェクトのリストを表示 --> 受信参照を含む] を右クリックして、それにつながるすべての強参照を検索します。

次に、[GC ルートへのパス] を右クリックします --> すべての参照を使用して、すべての参照をカウントし、このオブジェクトと GCRoot の間のパスを計算します。

結果を見ると、最終的に sCallBacks に到達しました。その左下隅に小さな円があります。これが実際に探している場所であり、MemoryLeakActivity が CallBackManager クラスの sCallBacks オブジェクトによって参照されていることを意味します。

上記で見つかった結果に基づいて、CallBackManager の sCallBacks を見つけるコードに移動して、ここで正確に何が起こっているかを確認してください。

publicstaticArrayList<CallBack> sCallBacks = new ArrayList<>();
复制代码

MemoryLeakActivityは静的変数sCallBacksによって参照されていますが、staticキーワードで変更された変数のライフサイクルはアプリのライフサイクル全体と同じ長さになるため、MemoryLeakActivityページを閉じた際には変数の参照関係を解放する必要があります。そうしないと、上記のメモリ リークの問題が発生します。したがって、この問題の解決は非常に簡単で、次のコード行を追加します。

@OverrideprotectedvoidonDestroy() {super.onDestroy();CallBackManager.removeCallBack(this);
}
复制代码

プロセスの概要:

  1. 初期観察にはメモリ プロファイラを使用します (利用可能なメモリは徐々に減少します)。

  1. メモリアナライザーによるコード確認と組み合わせる

5. オンラインメモリ監視ソリューション

オンライン メモリの最大の問題はメモリ リークです。メモリ ジッターとメモリ オーバーフローは、通常、メモリ リークによって引き起こされるメモリを解放できないことに関連しています。メモリ リークを解決できれば、オンライン メモリの問題は大幅に減少します。これらのオフライン ツールを使用して問題を直感的に発見して分析することができないため、オンライン メモリの監視は実際には非常に困難です。

5.1 従来のソリューション

①. シーンオンラインダンプを設定する

たとえば、アプリが 1 つのアプリの利用可能な最大メモリのより高い割合 (80% など) を占有している場合、Debug.dumpHprofData() を渡します。このコード行により、現在のメモリ情報をローカル ファイルに変換できます。

全体のプロセスは次のとおりです: メモリの 80% 以上 -> メモリ ダンプ -> ファイルを返す (ファイルが大きい可能性があることに注意してください。Wi-Fi 状態にして返します) -> MAT 手動分析

要約:

  • ダンプ ファイルが大きすぎるため、オブジェクトの数に直接関係しているため、切り取られる可能性があります。

  • アップロード失敗率が高く、分析が難しい

②. LeakCanaryをオンラインで利用する

  • LeakCanary がオンライン化

  • 事前に設定された漏れの疑いのあるポイント

  • 漏洩したポストバックが見つかりました

要約:

  • すべての状況に適しているわけではありません。疑いは事前に設定する必要があるため、包括性が制限されます。

  • 分析には時間がかかり、OOM が発生しやすいです (実際には、LeakCanary の分析プロセスは時間がかかり、分析プロセス中に OOM が発生する可能性が非常に高いことがわかっています)。

5.2 LeakCanary のカスタマイズ

  • 事前に設定された疑わしいポイント - 「自動的に疑わしいポイントを検出します (メモリ フットプリントが大きい人を疑います。メモリ オブジェクトが大きいと問題が発生する可能性が高くなります)。

  • 漏洩したリンクの分析が遅い (プリセットオブジェクトの各オブジェクトを分析) -> 保持サイズが大きいオブジェクトを分析 (分析負荷を軽減し、分析速度を向上)

  • OOM を分析 (メモリ スタックによって生成されたすべてのファイルをメモリにマップするため、より多くのメモリが必要になります) -> オブジェクトのトリミング、すべてがメモリにロードされるわけではありません

5.3 オンライン監視のための完全なソリューション

  • スタンバイ メモリ、キー モジュール メモリ、OOM レート

  • 全体および主要モジュールの GC 時間と GC 時間

  • 強化された LeakCanary 自動メモリ リーク分析

6. メモリ最適化スキル

最適化の一般的な方向性:

  • メモリーリーク

  • メモリスラッシング

  • ビットマップ

最適化の詳細:

  • LargeHeap 属性 (少し不正ですが、それでもシステムに適用する必要があります)

  • onTrimMemory、onLowMemory (システムによって与えられる低メモリ コールバックは、さまざまなコールバック レベルに従って一部のロジックを処理できます)

  • 最適化されたコレクションを使用する: SparseArray

  • SharedPreference の使用には注意が必要です (一度メモリにロードします)。

  • 外部ライブラリは注意して使用してください (大規模に検証された外部ライブラリを選択するようにしてください)

  • ビジネス アーキテクチャは合理的に設計されています (ロードされたデータはそのまま使用でき、無駄なデータをロードしてメモリが無駄になることはありません)

 

おすすめ

転載: blog.csdn.net/qq_25462179/article/details/132737973