How does the heap and stack work for instances and members of struct in C#?

我是研究僧i 提交于 2021-02-02 08:38:01

问题


I'm reading a book which says:

The variable representing an struct instance doesn’t contain a pointer to an instance; the variable contains the fields of the instance itself. Because the variable contains the instance’s fields, a pointer doesn’t have to be dereferenced to manipulate the instance’s fields. The following code demonstrates how reference types and value types differ

class SomeRef { public Int32 x; }
struct SomeVal { public Int32 x; }

static void ValueTypeDemo() {
   SomeRef r1 = new SomeRef();        // Allocated in heap
   SomeVal v1 = new SomeVal();        // Allocated on stack
   r1.x = 5;                          // Pointer dereference
   v1.x = 5;                          // Changed on stack
}

I'm from C background and little bit confused about the struct variable v1, I feel like v1.x = 5; still involve pointer dereference just like an array variable in C is a pointer to the address of first element in that array, I feel like v1 must be a pointer that points to the address(of stack, not heap of course) of first field in SomeVal, if my understanding is correct, then v1.x = 5; must involve pointer dereference too? If not, how a pointer is not involved if we want to access an random field in a struct as the compiler needs to generate the offset to the field, still a pointer has to be involved?


回答1:


In theory the runtime does not guarantee how the struct will be stored, it could could store it however it wants as long as the behavior is the same.

In practice your example will be stored as part of the methods stack frame. So v1 will reserve the space of the struct, i.e. 4 bytes. Access to the field of the struct will simply be converted to the corresponding field, the same way as if you used a int32 directly.

If the struct have multiple fields the compiler would simply add multiple offsets together, one to the beginning of the struct and one to the actual field. All of this is known at compile-time so it is no problem for the compiler to figure out this.

Note that while the CIL uses a stack based model, the jitter might optimize variables to be stored in registers instead. There is also the ref-keyword that allows a reference to a value type, somewhat similar to a pointer.




回答2:


Related answer:
How does a struct instance's virtual method get located using its type object in heap?

As said by @ Damien_The_Unbeliever, what follows is only valid for current computing technologies because .NET is a virtual platform. Actually and on Intel-like microprocessors (x86, x32, x64 and similar) since the CPU beginning and the invention of the stack registers, the behavior is like it is. But in the future, underlying things may be different with any other tech gen like quantum.

Instances of struct as members of a class are allocated with the object itself, so in the heap, but a local struct variable declared in a method is allocated in the stack.

Also, variables passed as parameters for a method always use the stack: reference as well as content of structures are PUSHed and POPed, therefore the limit of structures and anonymous types that are recommended to not be over used and to not be too big.

To simplify things and to understand, imagine that the heap is a whole room and the stack is a cupboard in this room.

This cupboard is for local value-types variables and references used to run the program, as well as to pass data between methods and to get results of these methods when they are functions and not procedures: references, value types, integral types, structs content, anonymous types and delegates are PUSHed and POPed to and from this cupboard as a temporary container.

The room is for objects themselves (we pass references of objects), except structs alone which are not in objects (we pass all the struct content, and it is the same when we pass a struct that is in a class, we pass the entire struct as a copy).

For example:

class MyClass
{ 
  MyStruct MyVar;
}

Is a struct variable "not alone" created in the head with the object when created anywhere.

But:

void MyMethod()
{ 
  MyStruct MyVar;
}

Is a local "alone" instance of the struct created in the stack as well as integers.

Thus if a class has 10 integers, only the reference is PUSHed in the stack when calling a method (4 bytes on x32 and 8 bytes on x64). But if it were a struct, it requires to PUSH 10 integers (40 bytes on x32 as well as x64).

In other words as you wrote: So then struct instances alone (thus, assigned to a local variable of struct type) are not stored in the Heap. But members of a class (thus, assigned to a field of struct type) are stored in the Heap.

That said:

  • Members (integral numeric and references pointer "values") of a struct in the heap are accessed using direct memory access using MOV opcodes and equivalent (virtual or targetted machine code).

  • Members of a struct in the stack are accessed using the stack register base+offset.

First is slow and second is faster.

How would the memory look like for this object?

What and where are the stack and heap?

Stack and heap in c sharp

Memory allocation: Stack vs Heap?

Stack and Heap allocation

Stack and Heap memory

Why methods return just one kind of parameter in normal conditions?

List of CIL instructions

.NET OpCodes Class

Stack register

The Concept of Stack and Its Usage in Microprocessors

Introduction of Stack based CPU Organization

What is the role of stack in a microprocessor?

To understand better and to improve your skills in computing, you may found interesting to investigate what is assembly language and how work the CPU. You can start with IL and modern Intel but it may be simpler, formative and complementary to start from the past 8086 to i386/i486.



来源:https://stackoverflow.com/questions/65896739/how-does-the-heap-and-stack-work-for-instances-and-members-of-struct-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!