3

.Net では、整数は値型です。つまり、スタックに格納されます。整数もクラスです (通常は System.Int32)。これらには、CompareTo、Equals などのメソッドがあります。したがって、スタック上で 4 バイト以上を取る必要があります。ただし、以下の例では、正確に 4 バイトかかることを示しています。

unsafe static void Main()
{
    int a = 2, b = 4;
    Console.WriteLine("Adress of a : {0}", (int)&a);
    Console.WriteLine("Adress of b : {0}", (int)&b);
    Console.WriteLine("Size of integer: {0}", (int)(&a) - (int)(&b));
}

出力:

Adress of a : 1372876
Adress of b : 1372872
Size of integer: 4

CLR は、整数およびその他の値型 (float、long、double など) に対して特別な処理を行いますか?

4

4 に答える 4

15

いいえ、それらが値型であるという事実は、それらがスタックに格納されているという意味ではありません。これは、変数が存在する場所に格納されることを意味します。

しかし、ねえ、ローカル変数ビジネスでロールバックしましょう。その時点で (キャプチャなどなしで)、それらスタック上に存在します。そして、それらは4バイトかかります。なぜ彼らはもっとかかるのでしょうか?メタデータで既に型が指定されているため、スタック上に vtable は必要ありません。どの仮想メソッドが呼び出されるかなどについてあいまいさはありません。

編集:Shawn のコメントで指摘されているように (ただし、もっとわかりやすくしたかったのですが)、System.Int32は構造体であり、クラスではありません。(実際、CLR は int のボックス化された値をカバーするシャドウ参照型を作成しますが、それは別の問題です。)

于 2009-03-01T21:52:42.230 に答える
5

したがって、それらはスタック上で 4 バイト以上を取る必要があります。

これは従いません。コンパイラランタイムは正確な型を認識しています。値型はさらにサブタイプ化できないため、「vtable」やその他のオブジェクト固有の動的ディスパッチ メカニズムは必要ありません。

値の型をボックス化してヒープに配置する場合、通常の .NET オブジェクト ヘッダーが必要です。

于 2009-03-01T21:52:37.657 に答える
4

メソッド内のローカル変数の場合、値型はスタックに割り当てられます。値型がクラスのメンバーである場合、ヒープ上のオブジェクトのメモリ領域の一部として割り当てられます。

値型変数は、参照型のように型を追跡するために追加のデータを必要としません。コンパイラは、値型変数がどこにあり、それらの型が何であるかを常に認識しているため、実際のデータに加えて追加のデータは必要ありません。Int32変数は常に4バイトになります。

参照型はヒープに割り当てられ、それを指す参照(またはそれ以上)があります。参照自体は実際には値型であるため、単なるポインターになり、コンパイラーはそれがどこにあり、どの型であるかを追跡します。参照のタイプは、それが指しているオブジェクトのタイプと同じである必要はないため、オブジェクトはタイプを追跡するために追加の情報を必要とします。たとえば、StringBuilderクラスのインスタンスを指すオブジェクト参照は次のとおりです。

object o = new StringBuilder();

ここで、コンパイラはそのタイプの参照がオブジェクトであることを追跡するため、単なるポインタ(32ビットアプリケーションでは4バイト)になります。StringBuilderオブジェクトはヒープに格納され、実際の型を追跡する2つの追加のポインターがあります。

値型はボックス化することもできます。つまり、ヒープ上のオブジェクトとして格納できます。これは、値型をオブジェクトにキャストするときに発生します。

object p = 42;

これにより、オブジェクトがヒープに割り当てられ、整数の値がヒープにコピーされます。このオブジェクトは、タイプを追跡するために追加のタイプ情報を必要とするため、ヒープ上で4バイトではなく12バイトを使用します(32ビットアプリケーションの場合)。

于 2009-03-01T22:17:05.323 に答える
0

タイプ定義とそのタイプのインスタンスに格納されている値には違いがあります。たとえば...

// type definition
public class Bla {}
// instance of type bla
public Bla myBla = new Bla();

基本的に、intのサイズは見た目(4バイト)ですが、ご存知のとおり、これは宣言する必要のあるメモリスペースのサイズです。

タイプ定義は他の場所に保存されます。CompareToなどのメソッドは、宣言するタイプのインスタンスごとに1回ではなく、この方法で1回だけ宣言されます。また、アプリケーションの目的で、フレームワークライブラリ自体の一部としてロードされるため、これらの定義は効果的に0スペースを占有します。

于 2011-05-20T12:47:43.053 に答える