Javaで未使用のオブジェクト参照をnull
に割り当てると、測定可能な方法でガベージコレクションプロセスが改善されますか?
Java(およびC#))の経験から、仮想マシンまたはJITコンパイラーを凌andすることはしばしば直観に反することがわかりましたが、同僚がこの方法を使用しているのを見てきました。これを取り上げるのが良い方法なのか、それともブードゥー教のプログラミング迷信の1つなのか、興味がありますか?
通常、いいえ。
しかし、すべてのもののように:それは依存します。 Java最近のGCは非常に良好であり、到達できなくなった直後にすべてをクリーンアップする必要があります。これは、ローカル変数のメソッドを終了した直後、およびクラスインスタンスがフィールドに対して参照されなくなりました。
明示的にnullにする必要があるのは、他の方法で参照されたままであることがわかっている場合のみです。たとえば、周りに保持される配列。配列の個々の要素が不要になったら、nullにすることができます。
たとえば、ArrayListの次のコード:
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
また、オブジェクトを明示的にnullにしても、参照が残っていない限り、オブジェクトが自然にスコープから外れた場合よりもすぐにオブジェクトが収集されることはありません。
どちらも:
void foo() {
Object o = new Object();
/// do stuff with o
}
そして:
void foo() {
Object o = new Object();
/// do stuff with o
o = null;
}
機能的に同等です。
良い記事は、今日の コーディングホラー です。
GCの動作方法は、ポインターを持たないオブジェクトを検索することです。検索の範囲はヒープ/スタックおよびその他のスペースです。したがって、変数をnullに設定すると、実際のオブジェクトはだれにも指されなくなり、GCされる可能性があります。
ただし、GCはその正確な瞬間に実行されない可能性があるため、実際には何も購入していない可能性があります。ただし、メソッドが(実行時間の点で)かなり長い場合は、GCがそのオブジェクトを収集する可能性が高くなるため、価値があるかもしれません。
また、コード最適化では問題が複雑になる可能性があります。nullに設定した後に変数を使用しない場合、null(実行する命令が1つ少ない)に設定する行を削除すると安全な最適化になります。したがって、実際には改善されていない可能性があります。
要約すると、は役立ちますが、決定論的ではありません。
私の経験では、ほとんどの場合、人々は必要以上にパラノイアから参照を無効にします。簡単なガイドラインを次に示します。
オブジェクトAがオブジェクトBを参照する場合およびこの参照は不要になりましたおよびオブジェクトAはガベージコレクションの対象外となり、フィールドを明示的にnullにする必要があります。囲んでいるオブジェクトがガベージコレクションを取得している場合、フィールドをnullにする必要はありません。 dispose()メソッドでフィールドを無効にすることは、ほとんど常に役に立ちません。
メソッドで作成されたオブジェクト参照をnullにする必要はありません。メソッドが終了すると、これらは自動的にクリアされます。このルールの例外は、非常に長いメソッドまたは大規模なループで実行している場合で、メソッドの終了前に一部の参照をクリアする必要がある場合です。繰り返しますが、これらのケースは非常にまれです。
ほとんどの場合、参照を無効にする必要はありません。ガベージコレクタの裏をかこうとするのは無意味です。結局、非効率的で読めないコードになってしまいます。
少なくともJavaでは、ブードゥー教のプログラミングではありません。 Javaのようなものを使用してオブジェクトを作成するとき
Foo bar = new Foo();
2つのことを行います。1つ目はオブジェクトへの参照を作成し、2つ目はFooオブジェクト自体を作成します。その参照または別の参照が存在する限り、特定のオブジェクトをgcすることはできません。ただし、その参照にnullを割り当てると...
bar = null ;
オブジェクトへの参照が他に何もないと仮定すると、ガーベッジコレクターが次に通過するときに解放され、gcで使用できます。
場合によります。
一般的に言えば、オブジェクトへの参照を保持する時間は短くなり、オブジェクトはより速く収集されます。
メソッドの実行に約2秒かかり、1秒のメソッド実行後にオブジェクトが不要になった場合、そのオブジェクトへの参照をクリアすることは理にかなっています。 GCが1秒後にそれを認識した場合、オブジェクトは引き続き参照され、次回は1分ほどでチェックする可能性があります。
とにかく、デフォルトですべての参照をnullに設定するのは時期尚早の最適化であり、特定のまれなケースでメモリ消費を測定できるほど減少させる場合を除き、誰もそれを行うべきではありません。
保持されているオブジェクトが非常に大きくない限り、変数をスコープ外に移動するのではなく、明示的に参照をnullに設定しても、ガベージコレクターの助けにはなりません。
通常、参照をnullに設定することは、このオブジェクトが完全に実行されるコードのREADERを意味し、これ以上は心配する必要はありません。
同様の効果は、ブレースの追加セットを入れて狭いスコープを導入することで達成できます
{
int l;
{ // <- here
String bigThing = ....;
l = bigThing.length();
} // <- and here
}
これにより、ネストされたブレースを離れた直後にbigThingがガベージコレクションされるようになります。
public class JavaMemory {
private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
public void f() {
{
byte[] data = new byte[dataSize];
//data = null;
}
byte[] data2 = new byte[dataSize];
}
public static void main(String[] args) {
JavaMemory jmp = new JavaMemory();
jmp.f();
}
}
上記のプログラムはOutOfMemoryError
をスローします。コメントを外す場合data = null;
、OutOfMemoryError
が解決されます。未使用の変数をnullに設定することは常に良い習慣です
一度ビデオ会議アプリケーションで作業していたときに、オブジェクトが不要になり次第、参照をnullにするために時間をかけると、パフォーマンスに大きな大きな違いがあることに気付きました。これは2003年から2004年のことであり、GCがさらにスマートになったことは想像に難くない。私の場合、毎秒数百のオブジェクトがスコープから出たり入ったりしていたため、GCが定期的に起動されたときにGCに気付きました。ただし、nullオブジェクトをポイントした後、GCはアプリケーションの一時停止を停止しました。
だからあなたのやっていることに依存します...
はい。
「実用的なプログラマー」p.292より:
参照をNULLに設定すると、オブジェクトへのポインターの数が1つ減ります(ガベージコレクターがオブジェクトを削除できるようになります)
OPは次のようなものを指していると思います:
private void Blah()
{
MyObj a;
MyObj b;
try {
a = new MyObj();
b = new MyObj;
// do real work
} finally {
a = null;
b = null;
}
}
この場合、VMはとにかくスコープを離れるとすぐにそれらをGCにマークしませんか?
または、別の観点から、項目を明示的にnullに設定すると、項目が範囲外になった場合に項目がGCされる前になりますか?その場合、VMはメモリが必要でないときにオブジェクトのGCに時間を費やす可能性があります。
プログラムの今後の実行では、一部のデータメンバーの値を使用して、プログラムの外部から見える出力を計算します。他のプログラムは、プログラムへの将来(および予測不可能)の入力に応じて、使用される場合と使用されない場合があります。他のデータメンバーは使用されないことが保証される場合があります。これらの未使用データに割り当てられたメモリを含むすべてのリソースが無駄になります。ガベージコレクター(GC)の仕事は、その無駄なメモリを排除することです。 GCが必要なものを削除することは悲惨なことになるので、使用されるアルゴリズムは保守的なものであり、厳密な最小値よりも多くを保持します。ヒューリスティックな最適化を使用して速度を改善する場合がありますが、実際には不要なアイテムを保持することはできます。 GCが使用する可能性のある多くのアルゴリズムがあります。したがって、プログラムに加えた変更がプログラムの正確さに影響しない場合でも、GCの動作に影響を与える可能性があり、同じジョブを実行するための実行が速くなるか、未使用のアイテムをより早く特定する可能性があります。したがって、unusddオブジェクト参照をnull
、理論上に設定するこの種の変更は、必ずしもブードゥー教とは限りません。
ブードゥー教ですか?これを行うJavaライブラリコードの部分があります。そのコードの作成者は、平均的なプログラマよりもはるかに優れており、ガベージコレクタの実装の詳細を知っているプログラマと協力します。 。それはそこにあることを示唆していますis時々利点。
参照の無効化がわずかに効率的であっても、これらのcodeい無効化でコードをペッパー化する必要があるというさの価値はありますか?それらは混乱するだけで、それらを含む意図コードを不明瞭にします。
ガベージコレクターの裏をかこうとするよりも最適化の良い候補がない、まれなコードベース(レアはまだそれを裏切ることに成功した開発者です)。あなたの努力はおそらくその代わりに他の場所で費やすほうが良いでしょう、その粗雑なXmlパーサーを捨てるか、計算をキャッシュする機会を見つけます。これらの最適化は定量化が容易であり、ノイズでコードベースを汚す必要はありません。
「依存する」
Javaについては知りませんが、.net(C#、VB.net ...)では、通常、オブジェクトが不要になったときにnullを割り当てる必要はありません。
ただし、「通常は必要ありません」ことに注意してください。
コードを分析することにより、.netコンパイラーは変数の寿命を適切に評価し、オブジェクトが使用されなくなったことを正確に判断します。したがって、obj = nullを記述した場合、実際にはobjがまだ使用されているように見えるかもしれません...この場合、nullを割り当てるのは逆効果です。
Nullを割り当てると実際に役立つ場合がいくつかあります。 1つの例として、長時間実行される巨大なコードや、別のスレッドまたはループで実行されるメソッドがあるとします。このような場合は、GCがもう使用されていないことを簡単に認識できるように、nullを割り当てると役立つ場合があります。
このための厳格なルールはありません。上記の手順を実行すると、コードにヌル割り当てが配置され、プロファイラーを実行して、何らかの方法で役立つかどうかを確認できます。ほとんどの場合、メリットが得られない可能性があります。
あなたが最適化しようとしている.netコードである場合、私の経験では、DisposeメソッドとFinalizeメソッドを慎重に扱う方が、実際にはnullを気にするよりも有益です。
トピックに関するいくつかの参照:
http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx
http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx