2009-03-01 14 views
3

では、整数は値型です。つまり、スタックに格納されます。 整数もクラスです(通常System.Int32)。彼らはCompareTo、Equals、...のようなメソッドを持っているので、スタック上で4バイト以上を取るべきです。 彼らは正確に4つのバイトを取ることがショー以下の例:.Net/C#:整数の実数は何ですか? .netの

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は整数であり、他の値型(のための特別な治療を負いませんフロート、長い、ダブル、... )?

+1

私はint32は構造であり、クラスではないと思います。 – Shawn

+0

これを64ビットOSで実行してみてください... –

+0

プラットフォームでもintは4バイトとして保持されます。 * native int *は別の問題です。悪い例は別の価値に終わるかもしれませんが、私は認めます – ShuggyCoUk

答えて

5

したがって、これらはスタックで4バイト以上必要です。

これはありません。コンパイラランタイムは、正確なタイプを認識します。値タイプはさらにサブタイプ化することができないので、「vtable」または他のオブジェクト固有の動的ディスパッチ機構が不要です。

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

15

いいえ、値型であるということは、スタックに格納されているわけではありません。それは彼らがwherever the variable livesに保存されていることを意味します。

しかし、ちょっと、地元の変数のビジネスで、その時点で(キャプチャなしなど)を実行してがスタックに住んでいます。そして、彼らは4バイトを取る。彼らはなぜより多くを取るのだろうか?スタック上にはvtableは必要ありません。メタデータは既にタイプを指定しているため、仮想メソッドが呼び出される方法についてのあいまいさはありません。

EDIT:Shawnによるコメントで指摘されていますがより明白にする)、System.Int32は、クラスではなく構造体です。実際には、CLRはintのボックス化された値をカバーするシャドウ参照型を作成しますが、それは別の問題です。

+0

ありがとうJon、 これは私の頭の中で物事を今明らかにする。 –

+0

は、メソッドが呼び出される変数の型をコンパイラが知っていて、そのメソッドがそのクラスで*直接*定義されている場合はクリアされます(仮想の場合はクラス/構造体の上書きが必要です) ILのすべての必要な情報が含まれているので、ボクシングは必要ありません – ShuggyCoUk

4

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

参照型とは異なり、値型変数では型の追跡に余分なデータは必要ありません。コンパイラは、値型変数の場所とその型を常に知っているので、実際のデータに加えて追加のデータは必要ありません。 Int32変数は常に4バイトです。

参照型はヒープ上に割り当てられ、参照型を指しています(またはそれ以上)。参照自体は実際には値型なので、ポインタにすぎません。コンパイラはその型とその型を追跡します。参照の型は、参照しているオブジェクトの型と同じである必要はないので、オブジェクトは型を追跡するために余分な情報を必要とします。例えば、StringBuilderクラスのインスタンスを指すオブジェクトリファレンス:

object o = new StringBuilder(); 

ここでコンパイラは、参照のタイプを追跡し、それはちょうど32におけるポインタ(4つのバイトであろうように、目的としますビットアプリケーション)。 StringBuilderオブジェクトはヒープに格納され、実際の型を追跡する2つの余分なポインタがあります。

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

object p = 42; 

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

+0

あなたのStringBuilderの例では、2つの余分なポインタは、参照またはオブジェクトの一部ですか?なぜ2つではなく1つでは?ありがとうございました。 –

+0

いいえ、8バイトは参照を含まず、ヒープ上のオブジェクトの一部です。仮想メソッドテーブルへのポインタと、それほどうまく文書化されていない4バイト以上...ここにいくつかの情報があります:http://stackoverflow.com/questions/489805/c-reference-variable-mem-allocation – Guffa

+0

「それがメソッド内のローカル変数ならば」、その変数はクロージャに取り込まれず、そのメソッドはイテレータブロックではありません; -p –

0

型定義し、例えば、その型のインスタンスの格納された値との差があります...

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

、本質的にint型の大きさは、それが(4バイト)と思われるようですが、あなたのようにこれは宣言するのに必要なメモリ容量の大きさです。

タイプ定義は別の場所に保存されます。CompareToのようなメソッドは宣言したそのタイプのインスタンスごとに一度だけ宣言され、フレームワークライブラリ自体の一部としてロードされるため、これらの定義は事実上0の空間を占有する。

関連する問題