Are These Objects's References on the Stack or on the Heap

Are these objects's references on the Stack or on the Heap?

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.

Where is allocated variable reference, in stack or in the heap?

myShip is a reference to a Ship object, myShip is on the method call stack, which is referred to as "the stack". When a method is called a block of memory is pushed onto the top the stack, that memory block has space for all primitives (int, float, boolean etc) and object references of the method, which includes the method parameters. The heap is where the memory for the actual objects is allocated.

So myShip is on the stack and the Ship object is on the heap.

Note each thread has its own stack but share the heap.

Are references stored on the heap or stack?

A reference is just an alias, and it is unspecified by the C++11 Standard whether it requires actual storage or not.

Per Paragraph 8.3.2/4 of the C++11 Standard:

It is unspecified whether or not a reference requires storage (3.7).

C++ : Why reference to stack allocated object treated same as reference to heap allocated object?

The value of &x in this context has to be stored somewhere in the compiled code, resulting in a different behavior than if you had a reference to an object allocated on the stack, right ?

How references work under the hood is up to the implementation. Each compiler is free to make them work however they want. But usually, the easiest solution is to treat T& like a T * const that can never be nullptr and whose address can never be taken. In cases where the referred object is known at compile time, then the reference can be optimized out and it's like it never existed. But this is also true of pointers. It's just that the extra property of not being addressable makes references a little bit easier to optimize out.

What you can be certain of is that the behavior will not be different based on how the referred object was created (dynamically or as a local object). Yes, the cases you show may result in the compiler doing different things, but the behavior of code is not a property of what the compiler does. This reasoning is backwards. The code in defines a strict behavior according to the language standard. Anything the compiler does has to leave that behavior intact, in so far as it respects what the standard says. So references have a behavior, and some uses of behavior will trigger different assembly to be generated but that result will behave the same.

Please note that references have a few extra requirements over pointers that makes the comparison with pointers a bit inaccurate. As an example see this question.

But why one cannot modify the address of a reference to a heap allocated object (since it has to be an l-value as far as i understand it, because of not being able to know it at compile time) ?

The reason you can't change the what a reference refers to is not a technical one. By design, you don't want to be able to change what it refers to even if it would be easy to implement that feature. This is because the immutable nature of references are considered an advantage. If you want a reference that is guaranteed to contain an address and that you can change to refer to other things, the language already provides pointers that can do this for you.

Why do we only have a "reference" type, and not "reference to stack allocated object" + "reference to heap allocated objects" types, since they are obviously not treated the same way in implementation ?

Again, it's not because the implementation treats different use cases of a feature that the interface should expose those differences to the developer. If you have are writing a void mutate(int &) function you want to handle all ints the same way, no matter how they were created or what optimizations the compiler might have come up. There isn't really a use case for a function that only works on stack allocated objects.

Why are reference types stored in heap

You can't generally store reference types on stack because the stack frame is destroyed upon method return. If you saved a reference to an object so it can be dereferenced after the method completes, you'd be dereferencing a non-existent stack location.

The HotSpot JVM can perform escape analysis and, if it determines that an object cannot possibly escape the method scope, it will in fact allocate it on the stack.

Where stored references to heap memory for reference types?

test variable is stored on stack - it holds address of object on heap. And object instance is stored on heap.

I suggest you to read .NET Type Fundamentals article by Jeffrey Richter:

When an object is allocated from the managed heap, the new operator
returns the memory address of the object. You usually store this
address in a variable. This is called a reference type variable
because the variable does not actually contain the object's bits;
instead, the variable refers to the object's bits.

In addition to reference types, the virtual object system supports
lightweight types called value types. Value type objects cannot be
allocated on the garbage-collected heap, and the variable representing
the object does not contain a pointer to an object; the variable
contains the object itself. Since the variable contains the object, a
pointer does not have to be dereferenced in order to manipulate the
object. This, of course, improves performance.

Struct has class reference then it will store on stack or heap C#

struct is a value type, and is therefore allocated on the stack

This is incorrect. A more correct statement would be "value types can be stored on the stack", see the truth about value types. The value type will probably be stored on the stack if given as a parameter, even if the jitter if free to store it wherever it damn pleases. But if the struct is part of a class, it will be stored on the heap, with all the other fields of the class.

Now, the reference to A will be stored as part of the struct, i.e. 8 bytes on x64. But the actual object it points to, including the int Value, will be stored on the heap.



Related Topics



Leave a reply



Submit