English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Androidプログラミングにおけるメモリオーバーフローの原因と防止方法の概説

このAndroidプログラミングのメモリオーバーフローの例と防止方法について説明しています。皆さんに参考にしていただくために、以下の通りです:

 AndroidのバーチャルマシンはレジスタベースのDalvikで、最大のヒープサイズは一般的に16M。しかし、AndroidはJava言語で書かれており、そのため、Androidのメモリメカニズムは多くの場合、Javaのメモリメカニズムと同等です。開発の初期段階では、メモリの制約問題がメモリオーバーフローなどの深刻な問題をもたらします。私たちがメモリを使用していない場合、Androidや他のプラットフォームで、他のプログラムを実行中に必要な状態を保存することを避け、デッドプロセスが引き起こすメモリ問題を最小限に抑え、プログラムを閉じるか状態を保存する際にメモリを解放することで、システムの動作の流暢性を向上させることができます。

Androidのメモリは主に以下のように表れます:

1Androidプラットフォームでは、長期間にわたってリソースの参照を保持することで、メモリが解放されないため、メモリリークの問題が多く発生します。例えば、Context(以下ではActivityを指します)が、あなたが最初のクラスのオブジェクトの状態を保持し、他のクラスのオブジェクトに状態を渡す必要がある場合、最初のクラスのオブジェクトを削除する前に、受け取るクラスのオブジェクトを解放する必要があります。注意すべきポイントは、JavaやAndroidのメモリメカニズムでは、顶点のノードがシステムのGCによってリサイクルされる前に、他のオブジェクトが参照していないことを確認する必要があることです。次の例を見てみましょう:

@Override
protected void onCreate(Bundle state) {
   super.onCreate(state);
   TextView label = new TextView(this);
   label.setText("Leaksare bad");
   setContentView(label);
}

このコードの意味は、私たちがTextViewのインスタンスを現在実行中のActivity(Context)にロードしていることを示しています。したがって、GCリサイクルメカニズムを通じて、Contextを解放するには、それを参照している一部のオブジェクトをまず解放する必要があります。もしそれがなければ、Contextを解放しようとすると、大量のメモリオーバーフローの発生が見られます。したがって、不注意ではメモリオーバーフローが非常に簡単に発生する可能性があります。オブジェクトを保存する際には、メモリリークも発生します。最も単純な例として、ビットマップ(Bitmap)を挙げます。例えば、スクリーンが回転すると、現在保持しているActivityの状態が破壊され、新しいActivityが生成され、新しいActivityの状態が保存されるまで新しいActivityが生成されるまで続きます。次の例を見てみましょう:

private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
   sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}

このコードは非常に高速ですが、同時に間違っています。メモリリークは画面の方向転換の際に発生しやすいです。表示されていないContextのインスタンスが保存されていると発見するかもしれませんが、描画をビューに接続する際に、Drawableがビューにコールバックを設定するため、実際には上記のコードでTextViewをアクティビティに描画する際に、このアクティビティを参照していることを示しています。リンク状況は以下のように表現できます:Drawable->TextView->Context。

したがって、Contextを解放したいと考えている場合でも、実際にはメモリに保存されており、解放されていません。

このような状況を避ける方法主に、スレッドが最もエラーが発生しやすいです。スレッドを軽視しないでください。Androidではスレッドが最もメモリリークを引き起こすことがあります。スレッドがメモリリークを引き起こす主な理由は、スレッドのライフサイクルが制御不能だからです。以下にコードがあります:

public class MyTest extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    new MyThread().start();
  }
  private class MyThread extends Thread{
    @Override
    public void run() {
      super.run();
      //do somthing
    }
  }
}

コードはシンプルですが、Androidでは新しい問題が発生します。画面を切り替えるとき(横画面か縦画面)、横画面または縦画面のActivityが再び作成されます。私たちは以前に作成されたActivityが回収されると思っていますが、実際はどうでしょうか?Javaのメカニズムは同じ感覚を与えてくれません。Activityを解放する前に、run関数が終了していないため、MyThreadは破棄されていません。その結果、それを参照するActivity(Mytest)も破棄されていないため、メモリリークの問題が発生します。

有人はAndroidが提供するAsyncTaskを使用することを好みますが、実際にはAsyncTaskの問題がさらに深刻です。Threadはrun関数が終了しない場合にのみメモリリーク問題が発生しますが、AsyncTaskの内部実装はThreadPoolExecutorを使用しており、生成されるスレッドのオブジェクトのライフサイクルは不確定で、アプリケーションは制御できません。したがって、AsyncTaskがActivityの内部クラスとして使用される場合、メモリリーク問題がより容易に発生します。

スレッド問題の改善方法には主に以下のようなものがあります:

① スレッドの内部クラスを静的内部クラスに変更してください。
② プログラム内でContextを保存する際には、できるだけ弱い参照を使用してください。

2.厄介なbitmap。。。

Bitmapは非常に厄介なオブジェクトです。メモリオブジェクトが大きい場合、システムのメモリ制限を超えたときにメモリリーク問題が明らかになります。
bitmapの解決策は、メモリに保存しないことやサンプリングレートを小さくすることです。多くの場合、私たちの画像のピクセル数が高いため、スマートフォンのスクリーンサイズに合わせて高ピクセルの画像をロードする必要がない場合、まず画像のサンプリングレートを下げて、元のUI操作を行います。

bitmapオブジェクトの参照を保存しない必要がある場合、ソフトリファレンスを使用することもできます。具体的な例はGoogleのソースコードにも多くあります。

以上を総括すると、メモリリークを避けるためには、以下のポイントに注意してください:

第一:Contextの長期的な保存を避けましょう(Contextを参照する場合は、参照オブジェクトとそのライフサイクルが一致するようにします)。

第二:Contextを使用する場合は、ApplicationContextを使用することをお勧めします。なぜなら、ApplicationContextのライフサイクルが長いため、参照の状況でメモリリークが発生しにくいからです。

第三:オブジェクトのライフサイクルをコントロールできない場合、Activity内でstatic変数を使用を避けましょう。staticの代わりにWeakReferenceを使用することをお勧めします。

第四:ガベージコレクタは正確にメモリを回収することを保証しません。そのため、必要な内容を使用する際には、主なライフサイクルを保持し、必要でないオブジェクトを迅速に解放することが重要です。Activityのライフサイクルが終了したら、onDestroyで参照している他のオブジェクトを解放してください。例えば:cursor.close()。

実際には、多くの面で少ないコードでプログラムを完了することができます。例えば:私たちはもっと多くの使用9パッチ画像など、多くの詳細な部分でメモリの問題を見つける価値があります。私たちがC/C++プログラムの「作成者は解放者」という原則について、私たちのメモリの管理はJavaやAndroidのGCメカニズムに劣るものではなく、さらに良いメモリ管理ができ、私たちの携帯電話の動作がより滑らかになります。

Androidに関連するさらに詳しい内容に興味がある場合は、以下の特集をチェックしてください:《Android開発におけるメモリとキャッシュの技術まとめ》、《Android開発入門と上級ガイド》、《Androidデバッグ技術とよくある問題の解決方法まとめ》、《Androidメディア操作技術まとめ(オーディオ、ビデオ、録音など)》、《Android基本コンポーネントの使い方まとめ》、《AndroidビューViewの技術まとめ》、《Androidレイアウトlayoutの技術まとめ》および《Androidコントロールの使い方まとめ》

この記事で述べたことが皆様のAndroidプログラムデザインに役立つことを願っています。

声明:この記事の内容はインターネットから取得しており、著作権者に帰属します。インターネットユーザーが自発的に貢献し、自己でアップロードしたものであり、このウェブサイトは所有権を持ちません。人工編集は行われていません。また、関連する法的責任を負いません。著作権侵害の疑いがある場合は、以下のメールアドレスにご連絡ください:notice#oldtoolbag.com(メールの際は、#を@に置き換えてください)で通報してください。関連する証拠を提供していただければ、該当する侵害内容をすぐに削除します。

おすすめ