2008-08-05 7 views
170

完了したら、すべてのオブジェクトをnull(VB.NETのNothing)に設定する必要がありますか?.NETで使用した後にオブジェクトをNull/Nothingに設定する

私は、IDisposableインターフェイスを実装するオブジェクトのインスタンスを破棄して、オブジェクトが廃棄された後も何らかのリソース(つまり、フォームのisDisposedというプロパティ)を残しておくことが不可欠であることを理解しています。私はそれがまだメモリに、または少なくとも部分的に存在すると思いますか?

オブジェクトが有効範囲外になると、ガベージコレクタの次のパスの準備が整ったことがわかります(これには時間がかかることがあります)。

これを念頭に置いて、nullに設定すると、システムがスピードアップしてメモリが解放されるため、スコープ内に存在しなくなり、悪影響を及ぼすことはありませんか?

MSDNの記事は例ではこれを実行していませんが、現時点ではこれを行うことはできません。 害を参照してください。しかし、私は意見が混ざり合っているので、コメントは役に立ちます。

+3

+1大きな質問です。コンパイラが課題を完全に最適化する状況を誰かが知っていますか?すなわち、異なる状況下で誰かがMSILを見て、オブジェクトをヌル(またはその欠如)に設定するためのILを指摘している。 –

答えて

66

カールは絶対に正しいです。使用後にオブジェクトをnullに設定する必要はありません。オブジェクトにIDisposableが実装されている場合は、そのオブジェクト(try .. finallyまたはusing()ブロックでラップされています)を終了したらIDisposable.Dispose()に電話してください。しかし、Dispose()を呼び出すことを忘れても、オブジェクトのfinalizerメソッドはDispose()を呼び出すはずです。

私はこれは良い治療法だと思った:

Digging into IDisposable

この

Understanding IDisposable

秒ので、GCとその経営戦略を推測しようとしているのいずれかのポイントがありませんそれは自己調整と不透明です。 Jeffrey Richter on the Windows Memory Modelと RichtersブックはCLR via C#章20は偉大な治療があります:一般的に

+5

nullに設定しないというルールは "難しく高速"ではありません...オブジェクトがラージオブジェクトヒープ(サイズが85K以上)に置かれた場合、オブジェクトをnullに設定するとGCが役に立ちますそれを使用して完了しました。 –

+0

私は限られた範囲に同意しますが、メモリ圧迫を経験しない限り、使用後にオブジェクトをnullに設定することにより、「早期に最適化」する必要はありません。 – Kev

+18

"早期に最適化しないでください"というこのビジネスは、CPUが高速化してCRUDアプリケーションが速度を必要としないため、遅くても心配する必要はありません。それだけでも私かもしれません。 :) – BobbyShaftoe

-1

一部のオブジェクトでは、リソースをメモリから強制的に削除する方法が考えられます。

+10

いいえ、そうではありません。 Dispose()はオブジェクトを収集しません*、それは、典型的には管理されていないリソースを解放する、確定的なクリーンアップを実行するために使用されます。 –

+1

決定論はマネージドリソースにのみ適用され、マネージドリソース(メモリ)には適用されません。 – nicodemus13

4

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

+2

これは本当ですが、コードをリファクタリングする必要があることを意味します。私はそれが意図された範囲外の変数を宣言する必要があるとは思わない。 –

+1

"変数"にオブジェクトフィールドが含まれていると理解されている場合、この答えは非常に意味があります。 「変数」は(メソッドの)「ローカル変数」のみを意味する場合、ここではニッチなケースについて話しています(通常の時間よりもはるかに長いメソッドなど)。 – stakx

7

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

それが参照をnullに理にかなっている場合があります。例えば、プライオリティ・キューのようなコレクションを契約書に書いているときは、クライアントがキューからオブジェクトを削除した後で、そのオブジェクトをアクティブに保つべきではありません。

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

全体として、本当に気にする必要はありません。コンパイラとGCが自分の仕事をするようにしてください。

8

、使用後にオブジェクトをゼロにする必要はありませんが、いくつかであり、ここでドットネットロックスのジェフリー・リヒターと内部の仕組みについての良い議論がしました私はそれが良い習慣だと思う。

オブジェクトがIDisposableインターを実装し、フィールドに格納されている場合、私はそれだけで破棄されたオブジェクトを使用しないように、それをゼロにするために良いことだと思います。次の並べ替えのバグは、痛みを伴うことができます:

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

それは、それを配置した後、フィールドをゼロにし、右のフィールドが再び使用されているラインでNullPtrExを取得するために良いことです。さもなければ、DoSomethingが何をしているかに応じて、いくつかの不気味なバグに遭遇するかもしれません。

+8

さて、廃棄されたオブジェクトは、既に破棄されている場合はObjectDisposedExceptionをスローする必要があります。これは、私が知る限り、場所のいたるところに定型的なコードを必要としますが、やはりDisposedは、とにかくひどく考えられたパラダイムです。 – nicodemus13

+2

'.Dispose()'にはCtrl + Fを押します。それを見つけたら、IDisposableを正しく使用していません。使い捨てオブジェクトの唯一の使用は、使用ブロックの範囲内にある必要があります。また、using-blockの後に、もはや 'myField'へのアクセス権もなくなります。そしてusingブロック内で 'null'に設定する必要はありません、using-blockはあなたのためにオブジェクトを破棄します。 – Suamere

6

nullの変数が必要と感じる場合は、コードが十分に構造化されていない可能性があります。

変数の範囲を制限するために、いくつかの方法があります。

{ 
    // Declare the variable and use it 
    SomeObject object = new SomeObject() 
} 
// The variable is no longer available 
:同様 スティーブトランビー

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

で述べたように

が、あなたは、単に中括弧を使用することができます

「見出し」を付けずに中括弧を使用すると、コードを実際に消去して理解しやすくなります。あなたは彼らと一緒に行われたときにnullに設定オブジェクトを避けるために

+0

私はカスタムローカルスコープを一度使ってみました(たいていはsmarta $$です)。同社は爆発した。 – Suamere

+0

別の注意:これは、C#コンパイラがIDisposableを実装するローカルスコープの変数を見つけ、そのスコープが終了するときに.Dispose(MOSTの時間)を呼び出すためです。しかし、... SQL接続は、.Dispose()が決して最適化されていないときには大変です。明示的な注意を必要とするタイプもあるので、私は個人的には常に明示的にしか行いませんので、私は噛まないようにしています。 – Suamere

33

もう一つの理由は、それが実際より長くのために生きているそれらを保つことができるということです。

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

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

はsomeTypeによって参照されるオブジェクトは「doSomethingの」を呼び出した後GC'dできるようになりますが、

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 will usually optimized away the assignment to nullだから、コードの両方のビットは同じになる。

+0

これは興味深い点です。私は、オブジェクトがスコープ内のメソッドが完了するまでオブジェクトがスコープから外れないと常に考えました。もちろん、オブジェクトがUseブロック内でスコープされているか、明示的にNothingまたはnullに設定されている場合を除きます。 –

+1

彼らが生き続けることを保証するための好ましい方法は、 'GC.KeepAlive(someType);を使うことです。http://ericlippert.com/2013/06/10/construction-destruction/ – NotMe

1

は、同様に、この記事を見てみましょう:ほとんどの部分についてhttp://www.codeproject.com/KB/cs/idisposable.aspx

を、nullにオブジェクトを設定することも効果はありません。サイズが84Kより大きい(ビットマップなどの) "ラージオブジェクト"を使用している場合は、必ず実行してください。

3

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

はい、完了した時点では、.Dispose()または.Close()を常に呼び出す必要があります。ファイルハンドル、データベース接続、または使い捨て可能なオブジェクトであるかどうか。それとは別に

はLazyLoadの非常に実用的なパターンです。

は、私が持っているとclass AObjAのインスタンスを言います。 Class APropBという公共財産がclass Bです。

内部的には、PropBはプライベート変数_Bを使用し、デフォルト値はnullです。 PropB.Get()を使用する場合、それは_PropBがnullであるかどうかをチェックし、それがある場合、B_PropBへのインスタンスを作成するために必要なリソースを開きます。その後、_PropBを返します。

私の経験に、これは本当に便利なトリックです。ヌルへの必要性がでてくる

はあなたが_PropBの内容はAの以前の値の子であったことを何らかの方法でAをリセットするか、変更された場合、あなたはとてもLazyLoadにリセットすることができます廃棄し_PropBをゼロにする必要がありますコードで必要な場合は正しい値を取得します。

_PropB.Dispose()を実行した直後で、LazyLoadのヌルチェックが成功すると予想した直後は、nullにはならず、失効したデータが表示されます。事実上、Dispose()の後にそれをヌルにする必要があります。

確かにそれはDispose()_PropBで、Dispose(したがってほとんど範囲外)の呼び出し元関数の外にあるこの動作を示しているコードを持っています。まだヌルではなく、失効したデータはまだそこにあります。

最終的には、配置されたプロパティが出ヌルますが、それは私の観点から、非決定的となっています。

コア理由は、dbkk暗示のように、親コンテナ(PropBObjA)はDispose()にもかかわらず、スコープ内_PropBのインスタンスを保持していることです。

+0

手動でヌルに設定する良い例良いことである発信者のためのより致命的なエラーを意味します。 – rolls

5

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

次にあなたが行う可能性があり、処分の一部が正しく実装とSystem.ObjectDisposed例外をスローすることはできませんので、あなたは、二回処分を呼び出すにしたくないので。

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

私はあなたがスピードアップ無効化と GCをすることはできません、GCの実装の設計によって信じています。 GCがどのように実行されているかを心配しないでほしいと思うのですが、これはユビキタスのように扱います。あなたのために保護して見守っています...(頭が下がり、拳が空に上がります) ...

個人的には、自分で自己文書化の形式として変数を設定すると、変数をnullに設定することがよくあります。私は宣言し、使用し、その後nullに設定しません - それらがもう必要なくなった直後にnullです。私は明示的に言っています、「私はあなたと正式にやっています...行くでしょう...」

GC化された言語では無効になっていますか?いいえ、GCには役立つのですか?たぶん、確かにわかっていないかもしれませんが、設計上、私は本当にそれを制御することができませんし、今日のこのバージョンまたはそれに関係なく、将来のGC実装は私のコントロールを超えて答えを変える可能性があります。さらに、nullingが最適化されている場合は、それを想像してみてください。コメント

私の足跡に続く次の悪い愚か者に私の意図が明確になったら、 "かもしれない"がGCを時々助けてくれるかもしれません。ほとんどの場合、私はきちんとした感じがします。そして、モンゴはきれいに感じるのが好きです。 :)

私はこれを次のように見ています:プログラミング言語は、他人に意図とアイディアのアイデアを他人に伝えるために存在します。コンパイラは何をすべきかの仕事要求をします。 ) - CPUはあなたが使用した言語、タブ設定、コメント、文体強調、変数名などのようなものを与えることができます - CPUはレジスタとオペコードを知らせるビットストリームに関するものですそして回転させるメモリ位置。コードで書かれた多くのものは、指定した順序でCPUによって消費されるものに変換されません。私たちのC、C++、C#、Lisp、Babel、アセンブラなど、現実よりも理論であり、仕事の記述として書かれています。あなたが見るものは、アセンブラ言語でさえ、あなたが得るものではありません。

私は「不要なもの」(空白行のような)の考え方は、ノイズだけであり、コードを乱雑にしていることを理解しています。それは私のキャリアの初期の私でした。私はそれを完全に得る。この時、私はコードをより明確にする方向に傾いています。私のプログラムに50行もの「ノイズ」を加えているようなものではありません。ここやそこにはいくつかの行があります。

ルールには例外があります。揮発性メモリ、スタティックメモリ、レースコンディション、シングルトン、 "古くなった"データの使用、そしてそのような腐敗のシナリオでは、それは違います:自分のメモリを管理し、メモリがロックされていないためGCの宇宙 - 誰もがそれを理解することを願っています。残りの時間は、GC言語を使用しているため、必要性やパフォーマンスの向上を保証するのではなく、スタイルの問題です。

1日の終わりに、GCの対象となるものとそうでないものとを理解してください。適切に施錠、処分、無効化する。ワックスが入っていて、息を吸う。他のすべてについて私は言う:それが良いと感じたら、それを行う。あなたの走行距離は変わるかもしれません...

関連する問題