I would really appreciate if someone could tell me whether I understand it well:
class X
{
A a1=new A(); // reference on the stack, object value on the heap
a1.VarA=5; // on the stack - value type
A a2=a1; // reference on the stack, object value on the heap
a2.VarA=10; // on the stack - value type
}
Also both a1
and a2
references are on the stack, while their "object" values are on the heap. But what about VarA
variable, its still pure value type?
class A
{
int VarA;
}
Reference TypesA reference type variable contains a reference to data stored in memory, also known as the heap. The heap is most often used for data that has a longer life. You can have more than one variable point to the same referenced data. Objects are an example of a reference type.
Whenever an object is created, it's always stored in the Heap space and stack memory contains the reference to it. Stack memory only contains local primitive variables and reference variables to objects in heap space.
The reference is basically on the stack. The memory for the object is allocated in what passes for the heap.
ValueType , e.g. int , bool , char , enum and any struct ) can be allocated on the heap or on the stack, depending on where they were declared. If the value type was declared as a variable inside a method then it's stored on the stack. If the value type was declared as a method parameter then it's stored on the stack.
You are asking questions about implementation details, so the answer will depend upon the particular implementation. Let's consider a version of your program that actually compiles:
class A { public int VarA; }
class X
{
static void Main(string[] args)
{
A a1 = new A();
a1.VarA = 5;
A a2 = a1;
a2.VarA = 10;
}
}
here's what happens on Microsoft's CLR 4.0, running C# 4.0, in Debug mode.
At this point the stack frame pointer has been copied into register ebp:
Here we allocate heap memory for the new object.
A a1 = new A();
mov ecx,382518h
call FFE6FD30
That returns a reference to a heap object in eax. We store the reference in stack slot ebp-48, which is a temporary slot not associated with any name. Remember, a1 has not been initialized yet.
mov dword ptr [ebp-48h],eax
Now we take that reference we just stored on the stack and copy it into ecx, which will be used for the "this" pointer to the call to the ctor.
mov ecx,dword ptr [ebp-48h]
Now we call the ctor.
call FFE8A518
Now we copy the reference stored in the temporary stack slot into register eax again.
mov eax,dword ptr [ebp-48h]
And now we copy the reference in eax into stack slot ebp-40, which is a1.
mov dword ptr [ebp-40h],eax
Now we must fetch a1 into eax:
a1.VarA = 5;
mov eax,dword ptr [ebp-40h]
Remember, eax is now the address of the heap-allocated data for the thing referenced by a1. The VarA field of that thing is four bytes into the object, so we store 5 into that:
mov dword ptr [eax+4],5
Now we make a copy of the reference in the stack slot for a1 into eax, and then copy that into the stack slot for a2, which is ebp-44.
A a2 = a1;
mov eax,dword ptr [ebp-40h]
mov dword ptr [ebp-44h],eax
And now as you'd expect again we get a2 into eax and then deference the reference four bytes in to write 0x0A into the VarA:
a2.VarA = 10;
mov eax,dword ptr [ebp-44h]
mov dword ptr [eax+4],0Ah
So the answer to your question is that references to the object are stored in the stack in three places: ebp-44, ebp-48 and ebp-40. They are stored in registers in eax and ecx. The memory of the object, including its field, is stored on the managed heap. This is all on x86 in the debug build, of Microsoft's CLR v4.0. If you want to know how stuff is stored on the stack, heap and registers in some other configuration, it could be completely different. References could all be stored on the heap, or all in registers; there might be no stack at all. It totally depends on how the authors of the jit compiler decided to implement the IL semantics.
Strictly speaking, it is implementation-dependant. Usually, a .NET developer should not care about this things. As far as i know, in Microsoft's implementation of .NET, variables of value types are stored on the stack (when they are declared within a method), and data of reference-type objects is allocated on a managed heap. But, remember, when a value type is a field of a class, the class data itself is stored on a heap (including all value-type fields). Hence, don't mix semantics(value types vs reference types) with allocation rules. This things may or may not be correlated.
I think you might have have a slight misunderstanding...
Generally speaking, reference types go on the heap, and value types / locals I believe (may be wrong) go on the stack. However, your A1.VarA and A2.VarA examples are referring to a field of a reference type - which is stored together with the object on the heap...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With