Search code examples
c#memoryheap-memorydeclarationstack-memory

C# clarification on how heap and stack work, including argument pass by reference and value


So I come from Python and Javascript, Python where everything is an object and variables contain references to objects (mostly Python).

When I use this analogy to c# it's a little bit different of course. So I really need some clarification about some concepts.

Firstly, in C# there are references types and value types e.g int wow = 90; will be a variable with in the same memory space the value "90", no reference to heap.

Secondly, when I create an object in C# it is a reference type, meaning that there is a variable in stack that has a reference saved in it, a memory address in heap memory where the object is stored.

When I e.g object obj = new object(){...}; the "obj" variable will thus have a memory address stored in it (it is a pointer) to a place in heap memory where the object in stored.

I know in Python that when I change the "obj" variable to e.g an integer object, the object will get garbage collected (assuming no more references) since the integer object will literally be stored in a whole other place with a different memory address in memory, meaning that the "obj" variable will know contain a completely different reference (memory address).

In C# this seems to be a little bit different.

When I have a value type stored in stack in the memory space of the variable and copy the the variables into another variable, it will just copy the value.

Nevertheless, there is also a concept of copying by reference and this really confuses me.

I'm assuming that when i create an object in C# and it gets stored in heap, and I reassign that variable, it will just straight up kind of replace the existing object with a new one in heap, while containing the same memory address (kind of reusing the exact same memory space). Not how it would be in Python (private heap) there the variable would just reference a completely different memory address. This is a really important concept I need to know if I'm right.

Also, I don't get how passing arguments by reference works behind the scenes, this is the most important concept of this thread and I'd really appreciate an elaborate answer here because I might be completely wrong e.g:

... adonetorefparam( ref int i){
    i = i + 1;
    Console.WriteLine(i); **output 21**
}
int test = 20;
addonetorefparam(ref test);
Console.WriteLine(test) **output 21**

What actually happens does "ref test" kind of take the reference (memory address) of the "test" variable in stack and stores it into the "i" parameter, resulting in a change being made to "i" means that a change has been made to the memory space of variable "test" in stack, meaning that "i" will now containt hat value and conversely "test" too?

The problem with all other explanations I've looked at is that they were too technical or they were too basic and didn't get to the point.

If there's any video material or articles you can recommend me that'd also be extremely useful :)!

Have an amazing day!


Solution

  • I reassign that variable, it will just straight up kind of replace the existing >object with a new one in heap, while containing the same memory addresss.

    It will create a new memory address, since the old object does not get garbage collected until it leaves the scope where it was declared... it cannot overwrite that address immediately. The address is freed up later... similar to how objects work in Python as you explained.

    When I e.g object obj = new object(){...}; the "obj" variable will thus have a memory address stored in it (it is a pointer) to a place in heap memory where the object in stored.

    It is wrong to call the obj variable a pointer, as it doesn't actually "point" to the memory address, instead think of it as an alias for the memory address itself.

    Also, I don't get how passing arguments by reference works behind the scenes. ... a change has been made to the memory space of variable "test" in stack, meaning that "i" will now containt hat value and conversely "test" too?

    You are correct, passing the integer by ref allows you to change it's value indirectly using method parameters, and both variables will work on the same memory location.