Memory allocation: Stack vs Heap?
Asked Answered
T

9

90

I am getting confused with memory allocation basics between Stack vs Heap. As per the standard definition (things which everybody says), all Value Types will get allocated onto a Stack and Reference Types will go into the Heap.

Now consider the following example:

class MyClass
{
    int myInt = 0;    
    string myString = "Something";
}

class Program
{
    static void Main(string[] args)
    {
       MyClass m = new MyClass();
    }
}

Now, how does the memory allocation will happen in c#? Will the object of MyClass (that is, m) will be completely allocated to the Heap? That is, int myInt and string myString both will go to heap?

Or, the object will be divided into two parts and will be allocated to both of the memory locations that is, Stack and Heap?

Twiggy answered 20/12, 2010 at 6:2 Comment(1)
Does this answer your question? What and where are the stack and heap?Frozen
S
62

m is allocated on the heap, and that includes myInt. The situations where primitive types (and structs) are allocated on the stack is during method invocation, which allocates room for local variables on the stack (because it's faster). For example:

class MyClass
{
    int myInt = 0;

    string myString = "Something";

    void Foo(int x, int y) {
       int rv = x + y + myInt;
       myInt = 2^rv;
    }
}

rv, x, y will all be on the stack. myInt is somewhere on the heap (and must be access via the this pointer).

Start answered 20/12, 2010 at 6:8 Comment(2)
An important addendum is to remember that "the stack" and "the heap" are really implementation details in .NET. It's perfectly possible to create a legal implementation of C# that doesn't use stack-based allocation at all.Myatt
I agree they should be treated that way, but it's not entirely true that they are purely implementation details. It's explicitly noted in the public API documentation and in the language standard (EMCA-334, ISO/IEC 23270:2006) (i.e. "Struct values are stored 'on the stack'. Careful programmers can sometimes enhance performance through judicious use of structs.") But, yeah, if the speed of heap allocation is a bottleneck for your application, you're probably doing it wrong (or using the wrong language).Start
P
77

You should consider the question of where objects get allocated as an implementation detail. It does not matter to you exactly where the bits of an object are stored. It may matter whether an object is a reference type or a value type, but you don't have to worry about where it will be stored until you start having to optimize garbage collection behavior.

While reference types are always allocated on the heap in current implementations, value types may be allocated on the stack -- but aren't necessarily. A value type is only allocated on the stack when it is an unboxed non-escaping local or temporary variable that is not contained within a reference type and not allocated in a register.

  • If a value type is part of a class (as in your example), it will end up on the heap.
  • If it's boxed, it will end up on the heap.
  • If it's in an array, it will end up on the heap.
  • If it's a static variable, it will end up on the heap.
  • If it's captured by a closure, it will end up on the heap.
  • If it's used in an iterator or async block, it will end up on the heap.
  • If it's created by unsafe or unmanaged code, it could be allocated in any type of data structure (not necessarily a stack or a heap).

Is there anything I missed?

Of course, I would be remiss if I didn't link to Eric Lippert's posts on the topic:

Probably answered 20/12, 2010 at 6:9 Comment(18)
Except of course until it does actually matter, in which case it is helpful to understand what is actually going on.Dollarfish
Ed: Exactly when does it matter?Probably
@Gabe: It does matter where the bits are stored. E.g. if you're debugging a crash dump, you are not going to get very far unless you know where to look for objects/data.Copyist
Well, it would certainly matter when the cost of copying objects is high, assignment/passing semantics become important. If your objects are inherently large and you have a lot of them you can overflow the stack. When you have to worry about the cost of garbage collection. It's not a common thing to worry about when your working in C#, but all abstractions become leaky at some point, and any competent programmer should know how these things work. Writing it off as an "implementation detail" is ridiculous.Dollarfish
I would add that, when you understand the semantics, you don't worry about it at the wrong times, only when it is relevant.Dollarfish
Ed: Knowing that something is going to be stored on the stack is important when attempting to understand garbage collection behavior and that's about it (and that in itself is an advanced topic, not for a beginner like the OP). It doesn't matter for debugging a crash dump because the debug information generated by the compiler will tell the debugger where a variable is stored (hint: it might not be on the stack or the heap) and it isn't relevant to whether an object is copied either (value types are copied regardless of where they're allocated).Probably
"Knowing that something is going to be stored on the stack is important when attempting to understand garbage collection behavior and that's about it" - That is just so false that I don't feel the need to argue about it. Just because you don't work on projects where things like that matter doesn't mean that is true for all.Dollarfish
As far as pass by copy or copy of reference is concerned I was just expanding on the stack/heap a bit and going into general memory semantics.Dollarfish
Ed: I just can't imagine a situation besides GC optimization where it matters that an object is stored on the stack. If you know of one, please enlighted me.Probably
Ed: Whether an object is copied is a question of whether it's a value or reference type, not whether it's allocated on the stack or heap.Probably
The situations you missed are: if the value type is from unmanaged code accessed through an unsafe pointerthen it is possibly on neither the stack nor the managed heap. It might be on the unmanaged heap, or in some data structure that isn't even a heap. The whole idea that there is "the heap" is also a myth. There can be dozens of heaps. Also, if the jitter chooses to enregister the value then it is not on the stack or the heap, it is in a register.Carpo
Would a safe summary description, fitting for an elevator explanation, be "reference types are allocated on a heap, value types are allocated on a stack unless you have to 'reach through' a reference type to dereference them"? (barring of course unmanaged edge cases)Heel
@Bracketworks: You forgot about registers. A value type small enough to fit in a register need not ever be assigned a memory address. Also, this "reach through" may be due to a closure, so you can't tell by looking that it has actually happened.Probably
@Probably Yes, I did forget about registers ;) however I was including closures as a reference type. So "reference types are allocated on a heap, whereas value types are allocated on a stack unless they are enregistered, accessed through an unsafe pointer, or accessed through something on a heap (a reference type)"Heel
@Bracketworks: I believe that is technically correct, but my point was that you can't tell from looking at the declaration of a variable where it will be stored.Probably
Eric Lippert's Part Two was a fantastic read, thank you for the link!Let
This matters because it is asked in interviews but not in real life. :)Kazimir
@Kazimir FWIW I was asked this question at my interview. I did give an answer. But also did mention that such a knowledge isn't practically much useful for mobile development. My manager did agree. But honestly I think she had a valid case for knowing if her employee/developer is the curious kind or not. I mean turning a blind eye to something you here a lot doesn't seem good to meEwall
S
62

m is allocated on the heap, and that includes myInt. The situations where primitive types (and structs) are allocated on the stack is during method invocation, which allocates room for local variables on the stack (because it's faster). For example:

class MyClass
{
    int myInt = 0;

    string myString = "Something";

    void Foo(int x, int y) {
       int rv = x + y + myInt;
       myInt = 2^rv;
    }
}

rv, x, y will all be on the stack. myInt is somewhere on the heap (and must be access via the this pointer).

Start answered 20/12, 2010 at 6:8 Comment(2)
An important addendum is to remember that "the stack" and "the heap" are really implementation details in .NET. It's perfectly possible to create a legal implementation of C# that doesn't use stack-based allocation at all.Myatt
I agree they should be treated that way, but it's not entirely true that they are purely implementation details. It's explicitly noted in the public API documentation and in the language standard (EMCA-334, ISO/IEC 23270:2006) (i.e. "Struct values are stored 'on the stack'. Careful programmers can sometimes enhance performance through judicious use of structs.") But, yeah, if the speed of heap allocation is a bottleneck for your application, you're probably doing it wrong (or using the wrong language).Start
W
26

"All VALUE Types will get allocated to Stack" is very, very wrong; struct variables can live on the stack, as method variables. However, fields on a type live with that type. If a field's declaring type is a class, the values are on the heap as part of that object. If a field's declaring type is a struct, the fields are part of that struct where-ever that struct lives.

Even method variables can be on the heap, if they are captured (lambda/anon-method), or part of (for example) an iterator block.

Whitfield answered 20/12, 2010 at 6:9 Comment(3)
And don't forget boxing: if you have object x = 12; in a method, the 12 will get stored on the heap even though it's an integer (a value type).Probably
@Gabe: Value-type storage locations hold within themselves the fields (public and private) of a value type. Reference-type storage locations either hold null, or a reference to a heap object of appropriate type. For every value type there is a corresponding heap-object type; attempting to store a value type in a reference-type storage location will produce a new object of its corresponding heap-object type, copy all the fields to that new object, and store a reference to the object in the reference-type storage location. C# pretends the value type and the object type are the same, but...Arie
...such a viewpoint adds confusion rather than understanding. An unboxed List<T>.Enumerator which is stored in a variable of that type will exhibit value semantics, because it's a value type. A List<T>.Enumerator which is stored in a variable of type IEnumerator<T>, however, will behave like a reference type. If one regards the latter as a different type from the former, the difference in behavior is readily explainable. Pretending they're the same type makes it much harder to reason about them.Arie
M
3

Stack

The stack is a block of memory for storing local variables and parameters. The stack logically grows and shrinks as a function is entered and exited.

Consider the following method:

public static int Factorial (int x)
{
    if (x == 0) 
    {
        return 1;
    }

    return x * Factorial (x - 1);
}

This method is recursive, meaning that it calls itself. Each time the method is entered, a new int is allocated on the stack, and each time the method exits, the int is deallocated.


Heap

  • The heap is a block of memory in which objects (i.e., reference-type instances) reside. Whenever a new object is created, it is allocated on the heap, and a reference to that object is returned. During a program’s execution, the heap starts filling up as new objects are created. The runtime has a garbage collector that periodically deallocates objects from the heap, so your program does not run Out Of Memory. An object is eligible for deallocation as soon as it’s not referenced by anything that’s itself alive.
  • The heap also stores static fields. Unlike objects allocated on the heap (which can get garbage-collected), these live until the application domain is torn down.

Consider the following method:

using System;
using System.Text;

class Test
{
    public static void Main()
    {
        StringBuilder ref1 = new StringBuilder ("object1");
        Console.WriteLine (ref1);
        // The StringBuilder referenced by ref1 is now eligible for GC.

        StringBuilder ref2 = new StringBuilder ("object2");
        StringBuilder ref3 = ref2;
        // The StringBuilder referenced by ref2 is NOT yet eligible for GC.
        Console.WriteLine (ref3); // object2
    }
}    

In the above example, we start by creating a StringBuilder object referenced by the variable ref1, and then write out its content. That StringBuilder object is then immediately eligible for garbage collection, because nothing subsequently uses it. Then, we create another StringBuilder referenced by variable ref2, and copy that reference to ref3. Even though ref2 is not used after that point, ref3 keeps the same StringBuilder object alive—ensuring that it doesn’t become eligible for collection until we’ve finished using ref3.

Value-type instances (and object references) live wherever the variable was declared. If the instance was declared as a field within a class type, or as an array element, that instance lives on the heap.

Mamey answered 28/1, 2018 at 18:22 Comment(0)
C
1

simple measures

Value type can be stred on THE STACK ,it is the implementaional detail it can be allocated to the some futuristist data structure.

so, it is better to understand how value and reference type works , Value type will be copied by value that means when you pass a value type as a param to a FUNCTION than it will be copied by nature means you will have a total new copy.

Reference types are passed by reference ( againg do not consider reference will store a address again in some future versions ,it may be stored on some other data structures.)

so in your case

myInt is a int which is ecapsulated in a class which offcourse an reference type so it will be tied to the instance of the class which will be stored on 'THE HEAP'.

i would suggest , you can start reading blogs written by ERIC LIPPERTS.

Eric's Blog

Cabbageworm answered 20/12, 2010 at 7:7 Comment(0)
U
1

Each time an object is created in it goes into the area of memory known as heap. The primitive variables like int and double are allocated in the stack, if they are local method variables and in the heap if they are member variables . In methods local variables are pushed into stack when a method is invoked and stack pointer is decremented when a method call is completed. In a multithreaded application each thread will have its own stack but will share the same heap. This is why care should be taken in your code to avoid any concurrent access issues in the heap space. The stack is threadsafe (each thread will have its own stack) but the heap is not thread safe unless guarded with synchronisation through your code.

This link is also useful http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/

Uriniferous answered 6/4, 2015 at 18:34 Comment(0)
P
0

m is a reference to an object of MyClass so m is stores in the stack of main thread but the object of MyClass stores in the heap. Therefore myInt and myString store in the heap. Note that m is only a reference (an address to memory) and is on main stack. when m deallocated then GC clear the MyClass object from the heap For more detail read all four parts of this article https://www.c-sharpcorner.com/article/C-Sharp-heaping-vs-stacking-in-net-part-i/

Pelkey answered 30/3, 2018 at 12:50 Comment(0)
A
-1

As per the standard definition (things which everybody says), all Value Types will get allocated onto a Stack and Reference Types will go into the Heap.

This is wrong. Only local (in the context of a function) value types/arrays of value types are allocated on the stack. Everything else is allocated on the heap.

Albertoalberts answered 8/6, 2021 at 18:41 Comment(1)
primitives & structs is a bit pointless to say (although I didn't downvote you). Just remove primitives & and the statement is clearer and no less accurate.Tytybald

© 2022 - 2024 — McMap. All rights reserved.