著者:王Chenyan
オープニング
ある日、バックグラウンド統計はオンラインで多くのOOM
クラッシュ。シャオ・ワンは上司からすぐに調査するように緊急の命令を受けました!
Xiao Wangは、これは簡単ではないと考えました。クラッシュスタックを見て、数分で解決します。
そこで、Xiao Wangは急いでクラッシュの背景を開き、彼は唖然としました。同様に、作成から1つOOM
までの数十の異なるスタックがありました。View
new
String
Xiao Wangはほとんど叱られました:これは武道についてではありOOM
ません!
叱った後も問題を解決する必要があります。そうしないと、上司とどのように向き合いますか?
精神的な旅
落ち込んでいる間、Xiao Wangは突然、パフォーマンスの最適化に関する記事を読んだことを思い出しました。この記事ではAndroid Studio
、に統合されたProfiler
APPメモリが導入されました。
スタックに問題はないので、記事の方法を踏襲して運試しをするしかありません。
そこで、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 leak
XiaoWangは「」を含むキーワードを除外しましたissue
案の定PR
、デタッチビューでリクエストが開始された場合のメモリリークの修正に非常に近いタイトルがありました。
問題が修正され、新しいバージョンがリリースされたようです。そのため、Xiao Wangはすぐにバージョンをアップグレードして再テストしましたが、リークは発生しませんでした。
それで私はすぐにコードを提出し、興奮して上司にそれを見せびらかしに行きました!!!
ソースのトレース
振り返ってみると、Xiao Wangは、「やる気のある」プログラマーとして、リークの原因を突き止めなければならないと考えました。
そこで、もう一度開きましたPR
。多くの変更の中で、最終的に実際のコードの変更を見つけました。その他はテストケースでした。
Xiao Wangはため息をつきました。曲がったナッツはプロであり、2行のコードを変更した後、一連のテストケースを作成する必要があります。
Xiao Wangはついにリークの原因を突き止めました。ページをすばやく切り替えると、画像の読み込みを開始する前にページが破壊されることがありました。このときCoil
、View
オブジェクトは保存され、待機中View
detach
にが、これはすでにView
.stateになっているので、解放されることはなく、再び保持されます。これは大きなメモリを大量に消費することはので、上記のように大量のメモリを占有する状況が発生します。detach
Bitmap
View
Bitmap
Bitmap
解決策は、View
それが行われたかどうかDetach
、行われた場合は、漏れを避けるために直接解放することです。