AndroidオンラインOOMのトラブルシューティングプロセス

著者:王Chenyan

オープニング

ある日、バックグラウンド統計はオンラインで多くのOOMクラッシュ。シャオ・ワンは上司からすぐに調査するように緊急の命令を受けました!

Xiao Wangは、これは簡単ではないと考えました。クラッシュスタックを見て、数分で解決します。

そこで、Xiao Wangは急いでクラッシュの背景を開き、彼は唖然としました。同様に、作成から1つOOMまでの数十の異なるスタックがありましたViewnewString

Xiao Wangはほとんど叱られました:これは武道についてではありOOMません!

叱った後も問題を解決する必要があります。そうしないと、上司とどのように向き合いますか?

精神的な旅

落ち込んでいる間、Xiao Wangは突然、パフォーマンスの最適化に関する記事を読んだことを思い出しました。この記事ではAndroid Studio、に統合されたProfilerAPPメモリが導入されました。

スタックに問題はないので、記事の方法を踏襲して運試しをするしかありません。

そこで、Xiao WangProfilerは、IDEの下部にある目立たない ""パネルをクリックしました。彼の目を引いたのは、

Xiao WangはMEMORYコラムこれはメモリ使用量ではありませんか?

さて、データは完全ですが、OOMそれシャオ・ワンは再び彼の人生を疑うようになりました...

「動かさないと何も見えません。メモリは動的に割り当てられます。」

Xiao Wangは、たくさんあるのでOOM、APPの共通ページが原因であると考えたので、Xiao Wangは、メモリの傾向を観察しながら、頻繁に使用するページを前後に切り替え始めました。

何度も試みた後、Xiao Wangは、アプリケーションのメモリ使用量が実際に増加していることを発見しました。手動操作を行っGCた後依然として高いままです。

Xiao Wangは、インタビューブックで「GC復元ので、GC不正確なデータを避けるために手動でクリックしました。

Javaヒープはからに15.7MB上昇19.3MBます。大きな問題ではないようですがNative、とんでもない、いい人です。実際にはからに56.1MB上昇97.5MBし、数分で上昇します。40MB+

Xiao Wangは大喜びし、ついに記憶の問題を発見しました!釣りをしているときにもっと記事を読んでも害はないようです。

ただし、メモリが異常であることを知っていても、どのコードが原因であるかを特定することはできません...

Xiao Wangは落ち着いてパターンを観察し続けましたが、最終的にAページから飛び出すたびにメモリが数メガバイト増加し、回復GCできなかったため、このページに何か問題があるはずです。

そこで、Xiao Wangは、メモリリークの原因を見つけることを期待して、このページのコードを叱り、読み始めました。私の心の中で、どの**がメモリリークのコードを書いたかを見てみましょう

Xiao Wangはコードを一語一語読んでいます:しかし問題はありません、それはただの普通のリストページであり、それはまだRecyclerView実装されています、それは何も悪いことではありません

今回、シャオ・ワンはまた困惑しました。シャオ・ワンは夜明け前に倒れないと思ったので、記事Profilerの。このDump機能を使えば、現在の記憶のスナップショットを簡単に見ることができます。何か見つけられるかもしれません。 ?

いいやつ、それはとても多くの記憶Bitmapをとっので、シャオ・ワンはインタビューの本をもう一度考えました

Android 2.3.3(APIレベル10)以前のバージョンでは、ビットマップオブジェクトとオブジェクト内の対応するピクセルデータは別々に保存され、ビットマップは仮想マシンのヒープに保存され、ピクセルデータはネイティブに保存されますメモリー。

Android 3.0(APIレベル11)からAndroid 7.1(APIレベル25)まで、ビットマップオブジェクトとそのピクセルデータは仮想マシンのヒープに保存されます。

Android 8.0(APIレベル26)以降、ビットマップオブジェクトは仮想マシンのヒープに保存され、対応するピクセルデータはネイティブヒープに保存されます。

XiaoWangがテストした携帯電話はAndroid10であり、BitmapデータはNativeヒープため、基本的Bitmapにメモリリークが発生していることが確実です。大きな前進ですが、それでも理由を見つけることができません。

Xiao Wangは、オブジェクトをクリックすると、すべてのインスタンスの参照チェーンを表示できることを発見しました。これにより、Xiao Wangは幸せになり、XiaoWangも非常に疑わしい参照チェーンを発見しました。

これはCoilMemory Cacheものではありませんが、ここにキャッシュがあります。なぜそれがリークされるのですか?このオープンソースライブラリにバグがあるのでしょうか?

Xiao WangはRealMemoryCache、この

これはLRU実装一見問題ないようです

私はそれを注意深く研究する時間がありません、Xiao Wangは自分自身に考えました、オープンソースコミュニティの誰かがこの問題を報告したかどうか見てみましょう、memory leakXiaoWangは「」を含むキーワードを除外しましたissue

案の定PRデタッチビューでリクエストが開始された場合のメモリリークの修正に非常に近いタイトルがありました。

問題が修正され、新しいバージョンがリリースされたようです。そのため、Xiao Wangはすぐにバージョンをアップグレードして再テストしましたが、リークは発生しませんでした。

それで私はすぐにコードを提出し、興奮して上司にそれを見せびらかしに行きました!

ソースのトレース

振り返ってみると、Xiao Wangは、「やる気のある」プログラマーとして、リークの原因を突き止めなければならないと考えました。

そこで、もう一度開きましたPR。多くの変更の中で、最終的に実際のコードの変更を見つけました。その他はテストケースでした。

Xiao Wangはため息をつきました。曲がったナッツはプロであり、2行のコードを変更した後、一連のテストケースを作成する必要があります。

Xiao Wangはついにリークの原因を突き止めました。ページをすばやく切り替えると、画像の読み込みを開始する前にページが破壊されることがありました。このときCoilViewオブジェクトは保存され、待機中View detachにが、これはすでにView.stateになっているので、解放されることはなく、再び保持されます。これは大きなメモリを大量に消費することはので、上記のように大量のメモリを占有する状況が発生します。detachBitmapViewBitmapBitmap

解決策は、Viewそれが行われたかどうかDetach、行われた場合は、漏れを避けるために直接解放することです。

おすすめ

転載: blog.csdn.net/ajsliu1233/article/details/124271981