22

さまざまなバージョンの .NET で記述された多くのレガシー システムに取り組んでいて、さまざまな企業にまたがって、次のパターンの例を見つけ続けています。

public void FooBar()
{
    object foo = null;
    object bar = null;

    try
    {
       foo = new object();
       bar = new object();

       // Code which throws exception.
    }
    finally
    {
       // Destroying objects
       foo = null;
       bar = null;
    }

}

.NET でメモリ管理がどのように機能するかを知っている人にとって、この種のコードは非常に不要です。nullガベージ コレクターは、古いオブジェクトを収集できることを伝えるために手動で割り当てる必要はありません。割り当てnullによって、オブジェクトをすぐに収集するように GC に指示することもありません。

このパターンは単なるノイズであり、コードが何を達成しようとしているのかを理解するのが難しくなります。

では、なぜ私はこのパターンを見つけ続けるのでしょうか? この習慣を教えている学校はありますか?nullメモリを正しく管理するために、ローカル スコープの変数に値を割り当てる必要がある言語はありますか? null私が認識していない明示的な割り当てに追加の価値はありますか?

4

14 に答える 14

22

これは、リソースの「解放」、不適切な GC 実装、および不適切な API に慣れている開発者によるFUDカーゴ カルト プログラミング( Daniel Earwickerのおかげ) です。

一部の GC は、循環参照にうまく対応できませんでした。それらを取り除くには、「どこか」でサイクルを断ち切らなければなりませんでした。どこ?まあ、疑わしい場合は、どこでも。それを1年間やると、指先に移ります。

また、フィールドを に設定するnullと、開発者として「何かを忘れる」ことを常に恐れているため、「何かをする」という考えが得られます。

最後に、明示的に閉じなければならない API があります。これは、「使い終わったらこれを閉じる」という実際の言語サポートがなく、GC と同じようにコンピューターに認識させるためです。つまり、クリーンアップ コードを呼び出さなければならない API と、呼び出さない API があります。これは最悪で、上記のようなパターンを助長します。

于 2010-06-28T12:25:57.203 に答える
8

メモリ管理とオブジェクトの有効期間に参照カウント戦略を使用した VB から来た可能性があります。Nothing(null と同等) への参照を設定すると、参照カウントが減少します。そのカウントがゼロになると、オブジェクトは同期的に破棄されました。メソッドのスコープを離れると、カウントは自動的に減分されるため、VB でもこの手法はほとんど役に立ちませんでしたが、次のコードに示すように、貪欲にオブジェクトを破棄したいという特別な状況がありました。

Public Sub Main()
  Dim big As Variant
  Set big = GetReallyBigObject()
  Call big.DoSomething
  Set big = Nothing
  Call TimeConsumingOperation
  Call ConsumeMoreMemory
End Sub

上記のコードでは、 によって参照されるオブジェクトはbig、 への呼び出しがなければ最後まで残りますSet big = Nothing。メソッド内の他の要素が時間のかかる操作であったり、より多くのメモリ負荷を生成したりする場合、これは望ましくない可能性があります。

于 2010-06-28T13:04:57.213 に答える
3

これは、明示的にポインターを null に設定することが標準であった C/C++ に由来します (ダングリング ポインターを排除するため) 。

free() を呼び出した後:

#include <stdlib.h>
{
    char *dp = malloc ( A_CONST );

    // Now that we're freeing dp, it is a dangling pointer because it's pointing
    // to freed memory
    free ( dp );

    // Set dp to NULL so it is no longer dangling
    dp = NULL;
}

従来の VB 開発者も、メモリ リークを防ぐために COM コンポーネントを作成するときに同じことを行いました。

于 2010-06-28T12:21:37.243 に答える
3

これは、古い Visual Basic など、決定論的ガベージ コレクションを使用し、RAII を使用しない言語でより一般的ですが、それでも不必要であり、循環参照を解除する必要がしばしばありました。したがって、おそらくそれは、いたるところでダムポインターを使用する悪い C++ プログラマーに起因する可能性があります。C++ では、二重削除を防ぐために、削除後にダム ポインターを 0 に設定することは理にかなっています。

于 2010-06-28T12:23:44.570 に答える
2

このパターンは、C#のファイナライズとC ++のファイナライズの違いを理解するために一時停止せずに、C ++コードをC#に変換したことによるものだと思います。C ++では、デバッグの目的で(デバッガーで参照が無効になっていることを確認できるように)、またはまれに、スマートオブジェクトを解放するために、デストラクタで無効にすることがよくあります。(それがReleaseと呼んで、コードの意味をメンテナに明確に伝えたいという意味である場合。)ご存知のように、これはC#ではほとんど意味がありません。

さまざまな理由から、このパターンはVB/VBScriptでも常に見られます。私はここでそれを引き起こす可能性があるものについて少し考えました:

http://blogs.msdn.com/b/ericlippert/archive/2004/04/28/122259.aspx

于 2010-06-28T15:26:33.453 に答える
2

私はこれを VBScript コード (従来の ASP) でよく見てきましたが、そこから来ていると思います。

于 2010-06-28T12:20:32.533 に答える
2

以前の C/C++ 開発者の間ではよくある誤解だったと思います。彼らは、GC がメモリを解放することを知っていましたが、いつ、どのように解放されるかを本当に理解していませんでした。ただそれをきれいにして続けてください:)

于 2010-06-28T12:21:04.967 に答える
1

これは C/C++ から来ており、既に解放されたポインターで free()/delete を実行するとクラッシュする可能性があり、NULL ポインターを解放しても何もしませんでした。

これは、この構成 (C++) が問題を引き起こすことを意味します。

void foo()
{
  myclass *mc = new myclass(); // lets assume you really need new here
  if (foo == bar)
  {
    delete mc;
  }
  delete mc;
}

これが機能する間

void foo()
{
  myclass *mc = new myclass(); // lets assume you really need new here
  if (foo == bar)
  {
    delete mc;
    mc = NULL;
  }
  delete mc;
}

結論: C#、Java、およびその他のガベージ コレクション言語では、IT はまったく必要ありません。

于 2010-06-28T12:21:53.280 に答える
1

fooローカル変数ではなくインスタンス変数であったという事実に由来する null を割り当てる規則である可能性があります。GC が参照を収集する前に参照を削除する必要があります。誰かが最初の文で寝て、すべての変数を無効にし始めました。群衆が続いた。

于 2010-06-28T12:23:57.163 に答える
1

わずかな変更を検討してください。

public void FooBar() 
{ 
    object foo = null; 
    object bar = null; 

    try 
    { 
       foo = new object(); 
       bar = new object(); 

       // Code which throws exception. 
    } 
    finally 
    { 
       // Destroying objects 
       foo = null; 
       bar = null; 
    } 
    vavoom(foo,bar);
} 

作成者は、以前に例外がスローされてキャッチされた場合に、優れた Vavoom (*) が不正なオブジェクトへのポインターを取得しないようにしたかったのかもしれません。防御的なコーディングにつながるパラノイアは、このビジネスでは必ずしも悪いことではありません。

(*) 彼が誰であるかを知っているなら、あなたは知っています。

于 2010-06-28T12:30:47.410 に答える
0

これは以前にいくつかの Java コードで見たことがあります。オブジェクトを破棄する必要があることを通知するために静的変数で使用されました。

ただし、静的変数以外に使用してもJavaでは意味がないため、おそらくJavaに由来するものではありません。

于 2010-06-28T17:26:03.263 に答える
0

VB 開発者は、メモリ リークの可能性を軽減するために、すべてのオブジェクトを破棄する必要がありました。VB 開発者が .NET / c# に移行したときに、これがどこから来たのか想像できます

于 2010-06-28T12:23:27.133 に答える
0

fooガベージ コレクションがどのように機能するかについての誤解、またはオブジェクトとオブジェクトbarが非常に大きいため、GC をすぐに起動させようとする努力のいずれかが原因であることがわかります。

于 2010-06-28T12:24:15.370 に答える
-4

これは、C++ コード、特にスマート ポインターに由来します。その場合.Dispose()、C# の a とほぼ同等です。

これは良い習慣ではなく、せいぜい開発者の本能です。nullGC が循環参照を壊すのを助けるかもしれないことを除いて、C# で代入することによる実際の価値はありません。

于 2010-06-28T12:26:10.820 に答える