7

私は Android/Java の初心者です (通常は PHP と JavaScript を使用します)。参照が間違った方法で使用された場合のアプリでのメモリ リークの問題に関する記事をいくつか読んだことがあるので、他の人の作業でよく見られることについて質問があります。

多くの人は、複数のメソッドでビューなどにアクセスする必要がある場合、アクティビティの作成中に割り当てられるプロパティでこれの参照を保持します。私が読んだこと(または少なくとも私が読んだことを理解したこと)から、これはメモリリークのコースの1つですか?

オブジェクトに ID を割り当ててから、各メソッドでそれらを検索する方がよいでしょうか? もしそうなら、動的に作成されたオブジェクトはどうですか?

4

4 に答える 4

2

正しく使えば良いが、そうでなければ悪い。

アクティビティの外にあるものを別のクラスに渡し、そのクラスの寿命がアクティビティの寿命よりも長い場合にのみ、リークします。アクティビティがフォアグラウンド アクティビティでなくなると、Android によってアクティビティが破棄される可能性があります。また、アクティビティの外部にある何かがそのアクティビティへの参照を保持している場合、ガベージ コレクターはメモリを解放してヒープに戻すことができません。

アクティビティ コンテキスト、静的、シングルトンには特に注意してください。

アクティビティ内のビューへの参照を単に保持することは、絶対に正常です。

悪い例 (疑似コード) を次に示します。

public class MyApplication extends Application{
    public static ImageView activityBackgroundImageView;
}

public class MyActivity extends Activity{

    ImageView iv = findViewById(R.id.myImageView);
    myApplication.activityBackgroundImageView= iv; // <==== LEAK

}

実際には、リークはありません。(if) myActivity が finished() または破棄された場合にのみリークします。

各オブジェクトには参照カウント (オブジェクトへの参照を保持するオブジェクトの数) があります。アクティビティで ImageView への参照を設定すると、参照カウントは 1 になります。次に、その参照を Application クラスにコピーします。注意。Java ではすべてが値で渡されるため、参照の値、正確には値のコピー、つまり同じオブジェクトへの新しい参照を渡します。ImageView の参照カウントは 2 になりました。

しばらくして、アクティビティを終了すると、参照カウントが減少します。今は一つです。ゼロ以外の参照カウントがあるため、ガベージ コレクターはその ImageView オブジェクトを解放できません。

もちろん、アプリケーション内の参照を null にすることで修正できますが、スパゲッティ コードができてしまいます。

于 2012-12-04T13:02:14.000 に答える
0

メモリ リークの原因に関するあなたの観察は、まったく正しくありません。

ビュー要素への参照を保存することはまったく問題ありません。これを行う方法とそれらを使用すると、メモリリークが発生する可能性があります。たとえば、静的参照の使用は避けてください。たとえば、ビットマップ イメージを静的に参照すると、サイモンが回答で指摘したように、ガベージ コレクションの問題が発生する可能性があります。

したがって、次のようにしても問題ありません。

class{
 private TextView myTextView;

onCreate()
 myTextView = findViewById(R.id.mytextview);

myMethod()
 myTextView.text = "hello view."

}

myMethod は単に利便性のために既存の参照を使用します。置くことを妨げるものは何もありません。

findViewById(R.id.mytextview).text = "hello view";

ただし、多くの参照がある場合、それは本当に読みにくいコードになります。そのため、ローカル スコープ変数を使用できます。

myMethod()
 TextView myTextView = findViewById(R.id.mytextview);
 myTextView.text = "Hello"
 .....

個人的な好みに応じて、必ずしもメモリ リークが発生するとは限りません。

ここでの問題は、findViewById が集中的な手順であるため、繰り返し呼び出したくないということです。リスト ビューは特にこの傾向があり、これに対応しないと速度が大幅に低下します。

したがって、リスト ビューでは、viewHolder パターンを実装している人がいます。ビューの子要素への参照を割り当てる小さなオブジェクト。このオブジェクトは、親ビューの Tag プロパティに割り当てられます。その後のビューへの呼び出し中に、ビュー タグ プロパティに viewHolder があるかどうかをテストします。含まれている場合は、子オブジェクトへの参照があるため、ビューの内容を更新する必要があるたびに findViewById を呼び出す時間と労力を節約できます。

非常に大まかなアイデアで、実装が少し異なります。viewHolder = new ViewHolder(); viewHolder.myTextField = findViewById(R.id.mytextview); myView.setTag(viewHolder) .... if (viewHolder) viewHolder.text = "hello"

これはリスト ビューでのみ使用することに注意してください。私はそれを一般的な経験則として使用していません。

リスト ビュー アダプターの効率的なビュー ホルダー パターンを検索します。

于 2012-12-04T13:40:30.103 に答える
0

ContextAndroid で言及しているリークの問題は、オブジェクトへの参照も保持するものへの参照が、UI に関連付けられていないものによって保持されている場合に発生します。ある時点でそのアクティビティがシステム内の何からも参照されなくなり ( の後onDestroy())、ガベージ コレクション ルート (グローバル変数など)からのビューへの参照がなくなるため、ビューを含むアクティビティ内でビューへの参照を保持します。 、ガベージ コレクションの対象です。つまり、アクティビティとそのビューの間に設定された循環参照は、そのアクティビティへの参照を保持しているユーザーがいなくなると、もはや問題ではなくなります

問題が発生するのは、アクティビティへの参照を送信することです。それ自体ContextUI およびアクティビティ ライフサイクル コールの外部にあります。ロケーションリスナーのようなものや、登録を忘れたもの。これにより、その参照が保持され、ツリー全体がガベージ コレクションの対象外になります。したがって、大きなリーク。

于 2012-12-04T13:00:26.603 に答える
0

答えてくれてありがとう、人々に問題を引き起こすアプリを作成する前に確認したかった.

安全対策として、参照を削除して再作成するために onStop と onRestart を追加しました。これにより、アプリがバックグラウンドにある間、この種のものが存在しないことが保証されますが、静的プロパティで参照を使用することはありません.

于 2012-12-10T17:56:48.690 に答える