6

ジョセフ・アルバハリによるC# 5.0の本で、私はこれを見つけました

ここに画像の説明を入力 ここでは、変数が最後に使用されたコード行を渡すとすぐに、それによって参照されるオブジェクトがガベージ コレクションの対象となります (つまり、そのオブジェクトへの参照を保持する変数が他にない場合)。

ただし、カリフォルニア大学バークレー校のこの講義によると、オブジェクトへの参照がスタック上に存在する限り、ガベージ コレクションは行われません。私の理解では、メソッドが戻るまで、変数はスタックに残ります。これは、メソッドが参照するオブジェクトは、メソッドが戻るまで生きていることを意味します。

これは本の間違いですか、それとも Java と .net ガベージ コレクションの動作が異なるのでしょうか?

4

4 に答える 4

7

ただし、カリフォルニア大学バークレー校のこの講義によると、オブジェクトへの参照がスタック上に存在する限り、ガベージ コレクションは行われません。

あなたが正しい。あなたが見逃しているのは、参照がスタックに存在しなくなったことです。

スタック上にオブジェクトを構築するコードの場合:

StringBuilder ref1 = new StringBuilder("object1");

変数ref1は、スタックのメモリ位置に格納されます

                 0x403730:
Stack Pointer -> 0x40372C: pointer to ref1
                 0x403728: saved value of EBP
                 0x403724: saved value of return address
                 0x403720

次の行が来ます:

StringBuilder ref2 = new StringBuilder("object2");

ポインタはどこref2に保存されますか? スタック上: はい。しかし、スタックのどこにもちろん、使用されていたのと同じメモリ位置でref1!:

                 0x403730:
Stack Pointer -> 0x40372C: pointer to ref2
                 0x403728: saved value of EBP
                 0x403724: saved value of return address
                 0x403720

別の値を単にスタックにプッシュするのはばかげています。

Stack Pointer -> 0x403730: pointer to ref2
                 0x40372C: pointer to ref1
                 0x403728: saved value of EBP
                 0x403724: saved value of return address
                 0x403720

ref1もう必要ないので、それはばかげているでしょう。

がガベージ コレクションの対象となるのはそのためref1です。これに対する参照はもうありません。

于 2013-07-05T23:44:46.523 に答える
5

本は正しいです。

.NET では、ガベージ コレクターはコード内で変数が使用されている場所に関する情報を持っており、変数が使用されなくなるとすぐに、オブジェクトはガベージ コレクションの対象になります。

(ただし、デバッガーをアタッチしてコードを実行すると、ガベージ コレクターの動作が変わります。変数が使用されている場所だけでなく、変数のスコープ全体でオブジェクトが保持されるため、デバッガーでオブジェクトを調査できます。 )

于 2013-07-05T23:14:29.450 に答える
4

私の理解では、メソッドが戻るまで、変数はスタックに残ります。これは、メソッドが参照するオブジェクトは、メソッドが戻るまで生きていることを意味します。

JIT は、オブジェクト参照 (「変数」) を最後に使用した後はいつでも自由に削除できるため、必ずしもそうであるとは限りません。

オブジェクトへの参照がスタックに存在する限り、ガベージ コレクションは行われません。

これは事実ですが、この変数が「スタック上に存在」しなくなると、コードと必ずしも一致しない方法で JIT が変更される可能性があります。

C# 5 では、いくつかのシナリオで予想よりも長く変数が保持されるようにメソッドが書き直される可能性があるため、これは非常に混乱を招く可能async性があります。

そうは言っても、ある時点でオブジェクトが適格であることを保証する必要がある場合は、オブジェクトを参照する変数をnull明示的に設定すると、いつ明示的に適格になるかを制御できます。

于 2013-07-05T23:15:47.197 に答える
2

これは、そのメソッドから生成された CIL コードです。

.method private hidebysig static void  Main(string[] args) cil managed
    {
      .entrypoint
      // Code size       46 (0x2e)
      .maxstack  2
      .locals init ([0] class [mscorlib]System.Text.StringBuilder ref1,
               [1] class [mscorlib]System.Text.StringBuilder ref2,
               [2] class [mscorlib]System.Text.StringBuilder ref3)
      IL_0000:  nop
      IL_0001:  ldstr      "object1"
      IL_0006:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor(string)
      IL_000b:  stloc.0     //here ref1 is stored on stack.
      IL_000c:  ldloc.0     //here it is loaded to be displayed by the console.writeline
      IL_000d:  call       void [mscorlib]System.Console::WriteLine(object)
      IL_0012:  nop        //from here on no more reference to ref1.
      IL_0013:  ldstr      "object2"
      IL_0018:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor(string)
      IL_001d:  stloc.1
      IL_001e:  ldloc.1
      IL_001f:  stloc.2
      IL_0020:  ldloc.2
      IL_0021:  call       void [mscorlib]System.Console::WriteLine(object)
      IL_0026:  nop        //and from here on ref2 and ref3 also.
      IL_0027:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
      IL_002c:  pop
      IL_002d:  ret
    } // end of method Program::Main
于 2013-07-06T00:49:19.220 に答える