5
public class MyClass
{
    public int Age;
    public int ID;
}

public void MyMethod() 
{
    MyClass m = new MyClass();
    int newID;
}

私の理解では、次のことが当てはまります。

  1. 参照 m はスタック上に存在し、MyMethod() が終了すると範囲外になります。
  2. 値型 newID はスタック上に存在し、MyMethod() が終了すると範囲外になります。
  3. new 演算子によって作成されたオブジェクトはヒープに存在し、オブジェクトへの他の参照が存在しないと仮定して、MyMethod() が終了すると、GC によって再利用可能になります。

これが私の質問です:

  1. オブジェクト内の値の型はスタックまたはヒープに存在しますか?
  2. オブジェクトの値型のボックス化/ボックス化解除は問題ですか?
  3. このトピックに関する詳細でありながら理解可能なリソースはありますか?

論理的には、クラス内の値の型はヒープにあると思いますが、そこに到達するためにボックス化する必要があるかどうかはわかりません。

編集:

このトピックの推奨読書:

  1. Jeffrey Richter による C# 経由の CLR
  2. Essential .NET by Don Box
4

6 に答える 6

9

クラスの値型の値は、マネージヒープ内のオブジェクトインスタンスと共存する必要があります。メソッドのスレッドのスタックは、メソッドの存続期間中のみ存続します。そのスタック内にのみ存在する場合、値はどのように持続できますか?

管理対象ヒープ内のクラスのオブジェクトサイズは、その値型フィールド、参照型ポインター、およびSyncブロックインデックスなどの追加のCLRオーバーヘッド変数の合計です。オブジェクトの値型フィールドに値を割り当てると、CLRはその値をその特定のフィールドのオブジェクト内に割り当てられたスペースにコピーします。

たとえば、単一のフィールドを持つ単純なクラスを考えてみましょう。

public class EmbeddedValues
{
  public int NumberField;
}

そしてそれで、簡単なテストクラス。

public class EmbeddedTest
{
  public void TestEmbeddedValues()
  {
    EmbeddedValues valueContainer = new EmbeddedValues();

    valueContainer.NumberField = 20;
    int publicField = valueContainer.NumberField;
  }
}

.NET FrameworkSDKが提供するMSIL逆アセンブラーを使用して、EmbeddedTest.TestEmbeddedValues()のILコードを確認する場合

.method public hidebysig instance void  TestEmbeddedValues() cil managed
{
  // Code size       23 (0x17)
  .maxstack  2
  .locals init ([0] class soapextensions.EmbeddedValues valueContainer,
           [1] int32 publicField)
  IL_0000:  nop
  IL_0001:  newobj     instance void soapextensions.EmbeddedValues::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.s   20
  IL_000a:  stfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_000f:  ldloc.0
  IL_0010:  ldfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_0015:  stloc.1
  IL_0016:  ret
} // end of method EmbeddedTest::TestEmbeddedValues

CLRは、スタック内のロードされた値「20」を、ロードされたEmbeddValuesのNumberFieldフィールドの場所に直接管理対象ヒープにstfldするように指示されていることに注意してください。同様に、値を取得するときは、ldfld命令を使用して、その管理対象ヒープの場所からスレッドスタックに値を直接コピーします。これらのタイプの操作では、ボックス化/ボックス化解除は行われません。

于 2008-08-24T06:11:55.997 に答える
2
  • 回答#1:ヒープ。彼の優れた「Essential.NetVol1」からドンボックスを言い換える

参照型(RT)は、常にヒープに割り当てられたインスタンスを生成します。対照的に、値型(VT)はコンテキストに依存します-ローカル変数がVTの場合、CLRはスタックにメモリを割り当てます。クラス内のフィールドがVTのメンバーである場合、CLRは、フィールドが宣言されているオブジェクト/タイプのレイアウトの一部として、インスタンスにメモリを割り当てます。

  • 回答#2:いいえ。ボクシングは、オブジェクト参照/インターフェイスポインタを介して構造体にアクセスした場合にのみ発生します。obInstance.VT_typedfieldはボックス化されません。

    RT変数には、参照するオブジェクトのアドレスが含まれています。2 RT varは、同じオブジェクトを指すことができます。対照的に、VT変数はインスタンス自体です。2 VT varは同じオブジェクト(構造体)を指すことができません

  • Ans#3:DonBoxのEssential.net / Jeffrey RichterのCLR(C#経由)。私は前者のコピーを持っています...しかし後者は.Netリビジョンのためにもっと更新されるかもしれません

于 2008-08-24T07:43:38.180 に答える
2
  1. オブジェクトが所有するすべての参照または値の型は、ヒープに存在します。
  2. int をオブジェクトにキャストしている場合のみ。
于 2008-08-24T03:52:14.523 に答える
2

これについて私が見た中で最も優れたリソースは、Jeffrey Richter による CLR via C# という本です。.NET 開発を行う場合は、一読の価値があります。そのテキストに基づいて、私の理解では、参照型内の値型は親オブジェクトに埋め込まれたヒープに存在します。参照型は常にヒープ上にあります。ボクシングとアンボクシングは対称的ではありません。ボックス化は、ボックス化解除よりも大きな懸念事項になる可能性があります。ボクシングの意志値型の内容をスタックからヒープにコピーする必要があります。これが発生する頻度によっては、クラスの代わりに構造体を使用しても意味がない場合があります。パフォーマンスが重要なコードがあり、ボックス化とボックス化解除が行われているかどうかわからない場合は、ツールを使用してメソッドの IL コードを調べます。IL に box と unbox という単語が表示されます。個人的には、自分のコードのパフォーマンスを測定してから、これが心配の対象になるかどうかを確認します。あなたの場合、これはそれほど重大な問題になるとは思いません。参照型内でこの値型にアクセスするたびに、スタックからヒープ (ボックス) にコピーする必要はありません。そのシナリオは、ボクシングがより意味のある問題になる場所です.

于 2008-08-24T04:58:41.900 に答える
1

オブジェクト内の値型はスタックまたはヒープに存在しますか?

ヒープ上。これらは、参照を保持するためのポインタと同じように、オブジェクトのフットプリントの割り当ての一部です。

オブジェクトのボックス化/ボックス化解除の値型は懸念事項ですか?

ここにはボクシングはありません。

このトピックに関する詳細でありながら理解しやすいリソースはありますか?

リヒターの本に+1票。

于 2008-08-24T05:55:30.937 に答える