1

ストックGalaxy S3で成長できる十分な空きヒープスペースを備えたOOMを実行しているアプリがあります。アプリは他のデバイスで正常に動作します。

従来の Java では、これは永久世代空間内での OOM によって引き起こされる可能性があることを知っていたので、Dalvik がこれをどのように処理するかを調べてみましたが、決定的なものは見つかりませんでした。Androids SDK には MemoryUsage と ManagementFactory の両方が欠落しているように見えるため、Java のように取得できません。

Android に永続的な世代空間があるかどうか、その内容を検査できるかどうか、サイズと空き容量を取得するにはどうすればよいか、Dalvik が JVM とは異なるこの空間に入るものを処理するかどうかなどを調べようとしています。

このスペースが存在しないか、可能性が低い場合は、他のアイデアも受け入れます。

アプリの情報を少し。OOM を実行している S3 は 4.1.2 を実行しています。アプリは約 12 ~ 25 MB のヒープを使用し、使用可能な最大ヒープ サイズは約 45 MB です。多くのローカル リソース イメージがあり、後でさらに多くの遅延読み込みが行われます。ビットマップを .recylce() しています。アプリは毎回ほぼ同じ場所でクラッシュします。クラッシュした箇所のコードをよく見てみましたが、異常は見当たりません。他のデバイスはこのコードを問題なく実行します。

4

1 に答える 1

1

ヒープの断片化の問題が発生しているようです。

十分な空き領域があるヒープで 1.2MB の割り当てに失敗しています。ヒープが完全に断片化されているため、システムはおそらく 1.2MB の連続した空のチャンクを見つけることができず、ヒープをさらに拡大することはできません。

理論的には、断片化の問題について心配する必要はなく、自動 GC が処理してくれます。

実際には、システム GC を支援することで素晴らしい結果が得られる場合があることを、私は何度も見てきました。

断片化の問題を回避するためのいくつかのアイデアを次に示します。

  1. System.gc()戦略的に配置された場所で手動で実行します。人気のある場所は、アクティビティ onDestroy のような大きなオブジェクトの破壊中です。他の場所は、ビットマップのような大きな割り当ての前です。大きなビットマップをデコードする前に、手動 GC を追加してください。後で GC の数を減らしたい場合は、さまざまなヒープ サイズ関数をクエリして、問題のあるメモリ条件の手動テストを追加します。

  2. システム GC の空きリソースをより速く支援します。これにより、そもそもヒープが断片化するのを防ぐことができます。その方法については、ネット上にたくさんの資料があります。私の頭の上からいくつか:

    • 小さな割り当てが頻繁に発生する場合は、オブジェクトのプールを作成し、新しいオブジェクトを割り当てる代わりにプール内のオブジェクトを再利用するなど、メモリの再利用スキームを採用してみてください。この最適化は、Android アダプターでよく見られます (リストビューでのビューの再利用など)。
    • 参照グラフから変数を明示的に切断し、簡単な GC 用にマークするために、変数が不要な場合は手動で変数を null に設定します (データ コレクションを明示的にクリアする場合も同様です)。
    • 文字列の連結など、多くの操作がある場合は不変クラスを避けStringBuilder、通常Stringの s の代わりに使用します
    • ファイナライザーを完全に避ける
    • 循環参照を避けるか、少なくともそれらの 1 つを弱参照に変更します
    • 一般的に、必要な場所で弱い参照を使用する

ヒープのごく一部しか使用していないときにヒープが巨大なサイズに成長しないようにすることで、成功の度合いを測定できます。

もう 1 つのアイデアは、1.2MB の割り当てを小さくすることです。より小さいイメージを使用するか、デコード中にそれらを再スケーリングします。

于 2013-07-30T06:32:08.900 に答える