176

すべてのオブジェクトをに設定する必要がありますnullNothingVB.NETで)あなたはそれらを終えたら?

.NETでは、それを実装するオブジェクトのインスタンスを破棄することが不可欠であることを私は理解しています。IDisposableいくつかのリソースを解放するためのインタフェースisDisposedフォーム内のプロパティ)、だから私はそれがまだメモリに、または少なくとも部分的に常駐できると思いますか?

また、オブジェクトがスコープ外に出ると、ガベージコレクタの次のパスに備えてコレクションの準備ができたことになります(ただし、これには時間がかかります)。

だからこれを念頭に置いてそれをに設定されますnullそれがもはや範囲にないことを解決する必要はなく、それらは何らかの悪い副作用であるのでメモリを解放するシステムをスピードアップするでしょうか?

MSDNの記事では例でこれを行うことは決してなく、現在はできないのでこれを行います。 害を見なさい。しかし、私は意見が混在しているので、コメントは役に立ちます。


  • +1素晴らしい質問です。コンパイラが代入を完全に最適化する状況を誰かが知っていますか?すなわち、誰かがさまざまな状況下でMSILを調べ、オブジェクトをnullに設定した(またはその欠如)ことにILを指摘しています。 - Tim Medora

13 답변


67

Karlは絶対に正しいので、使用後にオブジェクトをnullに設定する必要はありません。オブジェクトが実装している場合IDisposable、あなたが呼ぶことを確かめなさいIDisposable.Dispose()そのオブジェクトを使い終わったら(try..finallyまたは、using()ブロック)。あなたが電話することを忘れていなくてもDispose()オブジェクトのファイナライザメソッドが呼び出すべきですDispose()あなたのために。

私はこれが良い治療だと思いました:

IDisposableを掘り下げる

この

IDisposableについて

セルフチューニングで不透明なので、GCとその管理戦略を2回目で推測しようとしても意味がありません。 Dot Net Rocksに関するJeffrey Richterとの内部的な働きについては、ここで良い議論がありました。Windowsメモリモデルに関するJeffrey Richterと 裁判官の本C#によるCLR第20章にはすばらしい扱いがあります。


  • nullに設定しないことに関するルールは、オブジェクトがラージオブジェクトヒープに配置されている場合(サイズが85K以上)、「ハードで高速」ではありません。オブジェクトをnullに設定すると、GCに役立ちます。使い終わったら - Scott Dorman
  • 私は限られた範囲で同意します、しかし、あなたがメモリプレッシャーを経験し始めていない限り、私は時期尚早に最適化する必要はないと思います'使用後にオブジェクトをnullに設定する。 - Kev
  • この「ビジネス全体で時期尚早に最適化しないでください」。 「CPUが速くなっているのにCRUDアプリはスピードを必要としないので、遅くして心配しないでください。それは私だけかもしれません。 :) - BobbyShaftoe
  • それが本当に意味するのは、「ガベージコレクタは、あなたよりもメモリ管理の点で優れている」ということです。それは私だけかもしれません。 :) - BobRodes
  • @BobbyShaftoe:「時期尚早な最適化は良くない、いつも」と言うのはおそらく間違っている。 「極端に遅い」のように聞こえるのではなく、「極端に聞こえる」の反対の極端にジャンプすることです。合理的なプログラマはどちらも言いません。それはニュアンスとあなたの最適化について賢いことについてです。私は個人的にコードの明快さと、実際に多くの人(若い頃の自分を含む)を見たことがあるので、実際にテストのパフォーマンスについて心配しています。"パーフェクト"読みやすさが完全に撃たれている間、それだけでそれを100,000回の反復で0.1ms節約させるためだけに。 - Brent Rittenhouse

34

オブジェクトを使い終わったときにオブジェクトをnullに設定しないようにするもう1つの理由は、オブジェクトを実際に長期間使用できるようにするためです。

gt;

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is now eligible for garbage collection         

    // ... rest of method not using 'someType' ...
}

someTypeによって参照されるオブジェクトが "DoSomething"への呼び出しの後にGCされることを許可します

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is NOT eligible for garbage collection yet
    // because that variable is used at the end of the method         

    // ... rest of method not using 'someType' ...
    someType = null;
}

メソッドが終了するまで、オブジェクトを存続させることがあります。のJITは通常代入をnullに最適化しますそのため、コードの両方のビットが同じになります。


  • これは興味深い点です。スコープを設定する方法が完了するまで、オブジェクトはスコープから外れないようにすることを常に考えていました。もちろん、オブジェクトがUsingブロック内でスコープ指定されているか、明示的にNothingまたはnullに設定されていない限り。 - Guru Josh
  • 生きていることを確認するための好ましい方法は、使用することです。GC.KeepAlive(someType);見るericlippert.com/2013/06/10/construction-destruction - NotMe

15

いいえオブジェクトをnullにしないでください。あなたはチェックアウトすることができますhttp://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx詳細については、しかし、物事をnullに設定しても何もしません、あなたのコードを汚すことを除いて。


  • 共有リンク内のメモリに関する詳細な説明 - user2323308

7

また:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of


7

一般に、使用後にオブジェクトをnullにする必要はありませんが、場合によってはそれが良い習慣だと思います。

オブジェクトがIDisposableを実装し、フィールドに格納されている場合は、破棄されたオブジェクトを使用しないようにするために、それをnullにするのが良いと思います。次のようなバグは辛いことがあります。

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();

フィールドを破棄した後、そのフィールドをnullにして、そのフィールドが再び使用される行でNullPtrExを取得することをお勧めします。さもなければ、あなたは(DoSomethingが何をするかに正確に依存して)行のいくつかの不可解なバグにぶつかるかもしれません。


  • それがすでに破棄されている場合は、破棄されたオブジェクトはObjectDisposedExceptionをスローする必要があります。私の知る限りでは、これはあちこちで定型コードを必要としますが、それでもやはり、Disposedはよく考えられていないパラダイムです。 - nicodemus13
  • Ctrl + F.Dispose()。見つかった場合は、IDisposableを正しく使用していません。使い捨てオブジェクトの唯一の用途は、using-blockの範囲内です。ブロックを使用した後は、にアクセスできない場合もあります。myFieldもう。そしてusingブロックの中では、null必須ではありません、using-blockはあなたに代わってオブジェクトを破棄します。 - Suamere

7

あなたが必要としているのであれば、あなたのコードは十分にしっかりと構造化されていないのでしょう。null変数

変数の範囲を制限する方法はいくつかあります。

で述べたようにスティーブ・トランビー

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

同様に、あなたは単に波括弧を使うことができます:

{
    // Declare the variable and use it
    SomeObject object = new SomeObject()
}
// The variable is no longer available

私は、コードを本当に整理して理解しやすくするために、「見出し」を付けずに中括弧を使用することに気付きました。


  • 私は一度カスタムのローカルスコープを使ってみました(ほとんどはsmarta $$です)。会社は爆発した。 - Suamere
  • もう1つの注意:これは、c#コンパイラがIDisposableを実装するローカルスコープの変数を見つけ、そのスコープが終了したときに.Dispose(ほとんどの場合)を呼び出すためです。しかし... SQL接続は、.Dispose()が最適化されていないときには大きな1つの機会です。明示的な注意を必要とするタイプがいくつかあるので、私は個人的には常に物事を明示的に行うので、噛み付かないでください。 - Suamere

5

変数をnullに設定する必要があるのは、変数が範囲外にならず、それに関連付けられたデータが不要になったときだけです。それ以外の場合は必要ありません。


  • それは本当ですが、それはあなたがおそらくあなたのコードをリファクタリングするべきであることも意味します。意図した範囲外の変数を宣言する必要があるとは考えていません。 - Karl Seguin
  • "変数"がオブジェクトフィールドが含まれていると理解されている場合は、この答えは非常に理にかなっています。 " variable"の場合「ローカル変数」のみを意味します。 (メソッドの)次に、私たちはおそらくここでニッチなケースについて話しているでしょう(例えば、通常よりずっと長い時間にわたって実行されるメソッド)。 - stakx

5

通常はnullに設定する必要はありません。しかし、あなたのクラスにリセット機能があるとします。

Disposeの一部は正しく実装されていない可能性があり、System.ObjectDisposed例外をスローするため、disposeを2回呼び出すことは望ましくないためです。

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }


3

このような「使用後にオブジェクトをnullに設定する必要はない」というのは、完全に正確というわけではありません。変数を破棄した後にNULLにする必要がある場合があります。

はい、必ず電話をかけてください.Dispose()または.Close()あなたが終わったときにそれを持っているものに。ファイルハンドル、データベース接続、または使い捨てオブジェクトです。

それとは別に、LazyLoadの非常に実用的なパターンがあります。

インスタンス化したとしましょうObjAclass AClass Aというパブリックプロパティを持っていますPropBclass B

内部的には、PropBのプライベート変数を使用します_Bデフォルトはnullです。いつPropB.Get()使用されているかどうかを確認します_PropBnullの場合、インスタンス化に必要なリソースを開きます。B_PropB。それから戻る_PropB

私の経験では、これは本当に便利なトリックです。

nullにする必要があるのは、何らかの方法でAをリセットまたは変更した場合です。_PropBの以前の値の子でしたA、あなたは処分する必要があります_PropBそのため、LazyLoadは、コードで必要な場合に正しい値を取得するようにリセットできます。

あなたがするだけなら_PropB.Dispose()そしてLazyLoadのnullチェックが成功すると期待した直後にnullにはならず、古くなったデータを見ることになります。実際には、後にそれを無効にする必要がありますDispose()念のために。

私はそれがそうでなければいいと確信しています、しかし私はコードを持っています。Dispose()_PropBそして、Disposeを実行した呼び出し関数の外側(したがってほぼ範囲外)では、プライベートプロップはまだnullではなく、古いデータはまだ存在します。

最終的に、処分された財産は無効になりますが、それは私の見解からすると非決定的です。

dbkkが暗示しているように、根本的な理由は、親コンテナ(ObjAPropB)のインスタンスを保持している_PropBにもかかわらず、Dispose()


  • 手動でnullに設定する方法を示す良い例は、呼び出し側にとってより致命的なエラーを意味します。これは良いことです。 - rolls

1

null参照に意味がある場合がいくつかあります。たとえば、優先順位付きキューなどのコレクションを作成しているときや、契約上、クライアントがキューからそれらを削除した後は、それらのオブジェクトをクライアントから解放しないでください。

しかし、この種のことは長命のコレクションにおいてのみ重要です。キューが作成された関数の終わりを超えてキューが存続しない場合は、それほど重要ではありません。

全体として、あなたは本当に気にするべきではありません。あなたができるように、コンパイラとGCに任せましょう。


1

この記事も見てください。http://www.codeproject.com/KB/cs/idisposable.aspx

ほとんどの場合、オブジェクトをnullに設定しても効果はありません。あなたが必ずそうするべきである唯一の時はあなたがサイズが84Kより大きい(ラージオブジェクト)(ビットマップのような)である「ラージオブジェクト」を使っているならばです。


0

GCの実装者の設計により、できません。スピードアップ無効化を伴うGC。 GCがどのように/いつ実行されるのかについて心配しないでください。であることあなたを守り、見守っています...(弓が頭を下げ、拳が空へと昇ってきます)...

個人的には、自己ドキュメンテーションの形式として変数を使い終わったら、変数を明示的にnullに設定することがよくあります。宣言したり、使用したり、後でnullに設定したりしません。不要になった直後はnullにします。私は、「私は正式にあなたとやりました…消えて…」と明確に言っています。

GCの言語では無効化は必要ですか?いいえ。GCに役立ちますか?たぶん、いや、いや、確かにわからない、設計上、私は本当にそれを制御することができない、そしてこのバージョンでの今日の答えに関係なく、将来のGC実装は私の制御を超えて答えを変えるかもしれない。さらに、null化が最適化されている場合は、空想に過ぎません。コメントもしそうなら。

私の意図が私の足跡をたどる次の貧しい愚か者に対してより明確にするかどうか、そしてそれが「たぶん」場合によってはGCを支援することもありますが、それは私にとって価値があります。主にそれは私をきちんとしたそして明確に感じさせます、そしてMongoはきちんとして明確に感じるのが好きです。 :)

私はこのように見ます:プログラミング言語は他の人々に意図のアイデアとコンパイラに何をすべきかの仕事の要求を与えることを可能にするために存在します - コンパイラはCPUのために異なる要求に変換を要求しますどの言語、タブ設定、コメント、文体強調、変数名など、CPUがすべてのレジスタやオペコード、メモリ位置を調整するためのビットストリームについて教えてくれます。コードで書かれたものの多くは、指定した順序でCPUが消費したものに変換されません。私たちのC、C ++、C#、Lisp、Babel、アセンブラ、あるいは実際よりもむしろ理論であるものは何でも、作業宣言として書かれています。あなたが見るものはあなたが得るものではありません、はい、アセンブラ言語でさえも。

「不要なもの」(空白行など)の考え方は「ノイズにすぎずコードを雑然とさせること」にすぎません。それは私のキャリアの初期の頃でした。私は完全にそれを手に入れました。この時点で私はコードをより明確にするものに傾いています。私のプログラムに50行もの「ノイズ」を加えているわけではありません。

どの規則にも例外があります。揮発性メモリ、静的メモリ、競合状態、シングルトン、「古くなった」データの使用、およびそのような腐敗のシナリオでは、違います。自分のメモリを管理し、メモリの一部ではないため、アプロとしてロックおよび無効化する必要があります。 GCの宇宙 - 誰もがそれを理解しているといいのですが。 GCの言語の残りの部分は、必要性や保証されたパフォーマンスの向上ではなく、スタイルの問題です。

一日の終わりに、GCに適格なものとそうでないものを理解してください。適切にロック、破棄、および無効化する。ワックスオン、ワックスオフ。吸い込む、吐き出す。そして、他のすべてのもののために私は言う:それが気分が良ければ、それをしなさい。あなたの走行距離は変わるかもしれません...それがあるべきように...


-1

いくつかのオブジェクトは.dispose()リソースをメモリから強制的に削除するメソッド。


  • いいえ、違います。 Dispose()はではないオブジェクトを収集します - これは決定論的なクリーンアップを実行するために使用され、通常は管理されていないリソースを解放します。 - Marc Gravell
  • 決定論は管理対象リソースにのみ適用され、管理対象外リソース(つまりメモリー)には適用されないことに留意してください。 - nicodemus13

リンクされた質問


関連する質問

最近の質問