tags:

views:

1775

answers:

3

Hi, in .Net, integers are valuetypes, which means it stored on the stack. Integers are also class (System.Int32 usually). They have methods like CompareTo, Equals,...Thus, they should take more than four bytes on the stack. The example below show however that they take exactly 4 bytes:

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));
}

Output:

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

Does the CLR make a special treatment for integer and other valuetypes (float, long, double,...)?

+3  A: 

Thus, they should take more than four bytes on the stack.

This does not follow. The compiler and runtime knows the exact type. Value types cannot be further subtyped, so no need for "vtable" or other object specific dynamic dispatch mechanism.

When value types are boxed to put them on the heap, the normal .NET Object header is needed.

Richard
+11  A: 

No, the fact that they're value types doesn't mean they're stored on the stack. It means they're stored wherever the variable lives.

But hey, let's roll with the local variable business, at which point (with no captures etc) they do live on the stack. And they take 4 bytes. Why would they take more? There's no need for a vtable on the stack, because the metadata already specifies the type: there's no ambiguity as to what virtual methods will be called etc.

EDIT: As pointed out in a comment by Shawn (but I wanted to make it more obvious), System.Int32 is a structure, not a class. (In fact the CLR will create a shadow reference type to cover boxed values of ints, but that's a different matter.)

Jon Skeet
Thank you Jon,It makes things clear in my head now.
to be clear if the compiler knows the type of the variable on which a method is being invoked and said method is *directly* defined on that class (if virtual then there must be an override on the class/struct) then the call described in the IL contains all the required info, so no boxing is required
ShuggyCoUk
+3  A: 

A value type is allocated on the stack if it's a local variable in a method. If a value type is a member of a class, it will be allocated as part of the object's memory area on the heap.

A value type variable does not need any extra data to keep track of the type, as reference types does. The compiler always knows where the value type variables are and what their type is, so there is no extra data needed in addition to the actual data. An Int32 variable will always be four bytes.

A reference type is allocated on the heap, and it has a reference (or more) that points to it. The reference itself is actually a value type, so it will just be a pointer, the compiler keeps track of where it is and what type it is. The type of the reference doesn't have to be the same as the type of the object that it is pointing to, so the object needs extra information to keep track of the type. For example, an object reference pointing to an instance of the StringBuilder class:

object o = new StringBuilder();

Here the compiler keeps track of that type of the reference is object, so it will just be a pointer (4 bytes in a 32-bit application). The StringBuilder object is stored on the heap, and it has two extra pointers with it that keeps track of the actual type.

A value type can also be boxed, i.e. stored as an object on the heap. This occurs when you cast a value type to Object:

object p = 42;

This will allocate an object on the heap and copy the value of the integer into it. This object will need the extra type information to keep track of the type, so it will use 12 bytes on the heap instead of four (in a 32 bit application).

Guffa
For your StringBuilder example, the two extra pointers are part of the reference or the object? and why two and not only one? thank you.
No, the eight bytes are not including the reference, they are part of the object on the heap. A pointer to the virtual method table, and four more bytes that are not very well documented... Here is some more info: http://stackoverflow.com/questions/489805/c-reference-variable-mem-allocation
Guffa
Just to be picky: "if it's a local variable in a method" and that variable isn't captured into a closure, and the method isn't an iterator block ;-p
Marc Gravell