Javaオブジェクトをnullに設定しても、もう何もしませんか?


112

古い本をいくつか見ていて、Peter Haggerによる "Practical Java"のコピーを見つけました。パフォーマンスのセクションでは、null不要になったときにオブジェクト参照を設定することをお勧めします。

Javaでは、オブジェクト参照を設定してnullパフォーマンスまたはガベージコレクションの効率を向上させますか?もしそうなら、どのような場合にこれは問題ですか?コンテナクラス?オブジェクト構成?匿名の内部クラス?

これはコードでかなり頻繁に見られます。これは現在、古いプログラミングのアドバイスですか、それともまだ役に立ちますか?


2
それをプロファイルします。最新のランタイムでは、パフォーマンスやメモリフットプリントの大幅な増加は見られません。
Jason Coco、

12
@ジェイソン、それをプロファイル?これは、これに答えるのに十分な結果セットを取得するために、十分に大きなケースのセットをプロファイルすることを前提としています。そして、VMがGCとパフォーマンスの問題を隠すのに十分に最適化されている一連のケースは選びません。これが私がここでこれを求めている理由です。これが問題であるケースの感覚をつかむため。
SAL

回答:


73

これは、参照を無効にすることを考えていた時期に少し依存します。

オブジェクトチェーンA-> B-> Cがある場合、Aに到達できなくなると、A、B、Cのすべてがガベージコレクションの対象になります(他に何もBまたはCを参照していないと仮定)。たとえば、参照A-> BまたはB-> Cを明示的にnullに設定する必要はありません。

それとは別に、実際にはコレクション内のオブジェクトを扱っているため、ほとんどの場合、問題は実際には発生しません。通常、常に適切なremove()メソッドを呼び出して、リストやマップなどからオブジェクトを削除することを考えるべきです。

nullへの参照を設定するためのアドバイスがかつてあったケースは、特に、メモリを大量に消費するオブジェクトがスコープの途中で使用されなくなっ長いスコープにありました。例えば:

{
  BigObject obj = ...
  doSomethingWith(obj);
  obj = null;             <-- explicitly set to null
  doSomethingElse();
}

ここでの理論的根拠は、objがまだスコープ内にあるため、参照を明示的にnullにしないと、doSomethingElse()メソッドが完了するまで、ガベージコレクトできないことです。そして、これはおそらく現在のJVMにはもはや当てはまらないアドバイスです。JITコンパイラーは、特定のローカルオブジェクト参照が使用されなくなった時点で解決できることがわかります


2
ローカル変数はマシンによって最適化できます。クラス変数はできません。(スレッドプール上の)ワーカースレッドは、要求を処理した後、状態オブジェクトを解放しないため、ワーカースレッドに新しいタスク(古い状態オブジェクトを新しいタスクですばやく上書きする)が与えられるまで、それらのオブジェクトをメモリに固定しました。大きな状態オブジェクトと数百のワーカースレッド(大きなHTTPサーバーと考えてください)を使用すると、大量のメモリが保持およびコピーされる可能性がありますが、再び使用されることはありません。
ブライアンホワイト

1
私はおそらく追加する必要があります:上記のアドバイスは、正常に動作するライブラリ、正常に動作するVMなどを想定して、一般的に従うべきアドバイスです。たとえば、後にオブジェクトにハングするスレッドプールライブラリがある場合ジョブは終了しました。まあ、それは、スレッドプールライブラリのバグであり、オブジェクト参照をnullにすることで回避できる可能性がありますが、バグの少ないスレッドプールライブラリを使用することでも同様に回避できる可能性があります。そのようなバグが一般的な設計原則を変更するかどうかはわかりません。
Neil Coffey、2015年

25

いいえ、それは時代遅れのアドバイスではありません。ぶら下がっている参照は、特に、たとえば、ArrayList事前に割り当てられた配列を使用して拡張可能な配列コンテナー(など)を実装している場合は、依然として問題です。リストの「論理」サイズを超える要素はnullにする必要があります。そうしないと、解放されません。

「Effective Java 2nd ed、Item 6:Eliminate Obsolete Object References」を参照してください。


これは言語の問題ですか、それともVMの実装の問題ですか?
Pablo Santa Cruz、

4
これは「セマンティック」な問題です。基本的に、アレイを事前に割り当てているため、VMはそれを認識します。コンテナの「論理」サイズについては何も知りません。16要素の配列に基づくサイズ10のArrayListがあるとします。VMは、アイテム10..15が実際に使用されていないことを認識できません。それらのスロットにコンテンツがある場合、それらは解放されません。
Chris Jester-Young、

コンテナクラスの外はどうですか?内部オブジェクトが外部オブジェクトによって割り当て解除されないオブジェクト構成では。
SAL

7
@sal一般的な経験則では、参照できない場合はガベージコレクションが行われます。したがって、外部オブジェクトに別のオブジェクトへの参照が含まれている場合、内部オブジェクトに他の参照がないと想定して、外部オブジェクトの唯一の参照をnullに設定すると、孤立した参照を含むオブジェクト全体がガベージコレクションされます。
ubermensch 2009年

2
同じアイテム6で、あなたは言及しました:オブジェクト参照をnullにすることは、標準ではなく例外であるべきです。
ACV

10

インスタンスフィールド、配列要素

オブジェクトへの参照がある場合、そのオブジェクトはガベージコレクションできません。特に、そのオブジェクト(およびその背後にあるグラフ全体)が大きい場合、ガベージコレクションを停止している参照は1つしかなく、その参照はもう必要ありません。これは不幸な状況です。

病理学的なケースは、それを構成するために使用されたXML DOMツリー全体への非必須インスタンスを保持するオブジェクト、登録解除されなかったMBean、またはクラスローダー全体がアンロードされないようにするアンデプロイされたWebアプリケーションからのオブジェクトへの単一参照。

したがって、参照自体を保持するオブジェクトがとにかく(またはそれでも)ガベージコレクションされることが確実でない限り、不要になったすべてのものをnullにする必要があります。

スコープ付き変数:

スコープの終了前にローカル変数をnullに設定して、ガベージコレクターによって再利用され、「今後は使用不可」とマークできるようにする場合は、代わりに、より限定されたスコープに配置することを検討してください。 。

{
  BigObject obj = ...
  doSomethingWith(obj);
  obj = null;          //   <-- explicitly set to null
  doSomethingElse();
}

なる

{
  {  
     BigObject obj = ...
     doSomethingWith(obj);
  }    //         <-- obj goes out of scope
  doSomethingElse();
}

長くて平らなスコープは、一般的にコードの読みやすさにも悪影響を及ぼします。その目的のためだけに物事を分割するプライベートメソッドを導入することも、前例のないことではありません。


強い参照を参照している場合、はいこれは当てはまりますが、すべての参照に当てはまるわけではありません。Javaの弱い参照はガベージコレクションされる可能性があります。
James Drinkard 2013年

5

メモリが制限された環境(携帯電話など)では、これが役立ちます。nullを設定することにより、objetcは、変数がスコープ外になってgc化されるのを待つ必要がなくなります。

ただし、日常のプログラミングでは、Chris Jester-Youngが引用したような特別な場合を除いて、これは規則であってはなりません。


1

まず、オブジェクトをに設定するという意味ではありませんnull。以下で説明します。

List list1 = new ArrayList();
List list2 = list1;

上記のコードセグメントでは、メモリに格納されるオブジェクトのオブジェクト参照変数名list1を作成ArrayListしています。したがってlist1、そのオブジェクトとそれは変数にすぎません。また、コードの2行目では、list1to の参照をコピーしていますlist2。だから今私がそうするならあなたの質問に戻る:

list1 = null;

つまりlist1、メモリに格納されているオブジェクトlist2を参照していないため、参照するものは何もありません。あなたはの大きさを確認した場合のでlist2

list2.size(); //it gives you 0

したがって、ここに「オブジェクトによって保持されているメモリを解放することについて何も心配する必要はありません。プログラムで使用されなくなり、JVMが私を管理することがわかったときに、それを実行します」というガベージコレクタの概念が登場します。

コンセプトが明確になればいいのですが。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.