Introduction
Even though with the .NET framework we don't have to actively worry about memory management and garbage collection (GC), we still have to keep memory management and GC in mind in order to optimize the performance of our applications. Also, having a basic understanding of how memory management works will help explain the behavior of the variables we work with in every program we write. In this article, I'll cover the basics of the Stack and Heap, types of variables, and why some variables work as they do.
There are two places the .NET framework stores items in memory as your code executes. If you haven't already met, let me introduce you to the Stack and the Heap. Both the stack and heap help us run our code. They reside in the operating memory on our machine and contain the pieces of information we need to make it all happen.
Stack vs. Heap: What's the difference?
The Stack is more or less responsible for keeping track of what's executing in our code (or what's been "called"). The Heap is more or less responsible for keeping track of our objects (our data, well... most of it - we'll get to that later.).
Think of the Stack as a series of boxes stacked one on top of the next. We keep track of what's going on in our application by stacking another box on top every time we call a method (called a Frame). We can only use what's in the top box on the stack. When we're done with the top box (the method is done executing) we throw it away and proceed to use the stuff in the previous box on the top of the stack. The Heap is similar except that its purpose is to hold information (not keep track of execution most of the time) so anything in our Heap can be accessed at any time.
With the Heap, there are no constraints as to what can be accessed like in the stack. The Heap is like the heap of clean laundry on our bed that we have not taken the time to put away yet - we can grab what we need quickly. The Stack is like the stack of shoe boxes in the closet where we have to take off the top one to get to the one underneath it.

The picture above, while not really a true representation of what's happening in memory, helps us distinguish a Stack from a Heap.
The Stack is self-maintaining, meaning that it basically takes care of its own memory management. When the top box is no longer used, it's thrown out. The Heap, on the other hand, has to worry about Garbage collection (GC) - which deals with how to keep the Heap clean (no one wants dirty laundry laying around... it stinks!).
What goes on the Stack and Heap?
We have four main types of things we'll be putting in the Stack and Heap as our code is executing: Value Types, Reference Types, Pointers, and Instructions.
Value Types
In C#, all the "things" declared with the following list of type declarations are Value types (because they are from System.ValueType):
- bool
- byte
- char
- decimal
- double
- enum
- float
- int
- long
- sbyte
- short
- struct
- uint
- ulong
- ushort
Reference Types
All the "things" declared with the types in this list are Reference types (and inherit from System.Object... except, of course, for object which is the System.Object object):
- class
- interface
- delegate
- object
- string
Pointers
The third type of "thing" to be put in our memory management scheme is a Reference to a Type. A Reference is often referred to as a Pointer. We don't explicitly use Pointers, they are managed by the Common Language Runtime (CLR). A Pointer (or Reference) is different than a Reference Type in that when we say something is a Reference Type is a means we access it through a Pointer. A Pointer is a chunk of space in memory that points to another space in memory. A Pointer takes up space just like any other thing that we're putting in the Stack and Heap and its value is either a memory address or null.

Instructions
You'll see how the "Instructions" work later in this article...
How is it decided what goes where? (Huh?)
Ok, one last thing and we'll get to the fun stuff.
Here are our two golden rules:
- A Reference Type always goes on the Heap - easy enough, right?
- Value Types and Pointers always go where they were declared. This is a little more complex and needs a bit more understanding of how the Stack works to figure out where "things" are declared.
The Stack, as we mentioned earlier, is responsible for keeping track of where each thread is during the execution of our code (or what's been called). You can think of it as a thread "state" and each thread has its own stack. When our code makes a call to execute a method the thread starts executing the instructions that have been JIT-compiled and live on the method table, it also puts the method's parameters on the thread stack. Then, as we go through the code and run into variables within the method they are placed on top of the stack. This will be easiest to understand by example...
Take the following method.
public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}
Here's what happens at the very top of the stack. Keep in mind that what we are looking at is placed on top of many other items already living in the stack:
Once we start executing the method, the method's parameters are placed on the stack (we'll talk more about passing parameters later).
NOTE
The method does not live on the stack and is illustrated just for reference.

Next, control (the thread executing the method) is passed to the instructions to the AddFive() method which lives in our type's method table, a JIT compilation is performed if this is the first time we are hitting the method.

As the method executes, we need some memory for the "result" variable and it is allocated on the stack.

The method finishes execution and our result are returned.

And all memory allocated on the stack is cleaned up by moving a pointer to the available memory address where AddFive() started and we go down to the previous method on the stack (not seen here).

In this example, our "result" variable is placed on the stack. As a matter of fact, every time a Value Type is declared within the body of a method, it will be placed on the stack.
Now, Value Types are also sometimes placed on the Heap. Remember the rule, Value Types always go where they were declared? Well, if a Value Type is declared outside of a method, but inside a Reference Type, it will be placed within the Reference Type on the Heap.
Here's another example.
If we have the following MyInt class (which is a Reference Type because it is a class):
public class MyInt
{
public int MyValue;
}
and the following method is executing:
public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}
Just as before, the thread starts executing the method and its parameters are placed on the thread's stack.

Now is when it gets interesting...
Because MyInt is a Reference Type, it is placed on the Heap and referenced by a Pointer on the Stack.

After AddFive() is finished executing (like in the first example), and we are cleaning up...

we're left with an orphaned MyInt in the heap (there is no longer anyone in the Stack standing around pointing to MyInt)!

This is where the Garbage Collection (GC) comes into play. Once our program reaches a certain memory threshold and we need more Heap space, our GC will kick-off. The GC will stop all running threads (a FULL STOP), find all objects in the Heap that are not being accessed by the main program and delete them. The GC will then reorganize all the objects left in the Heap to make space and adjust all the Pointers to these objects in both the Stack and the Heap. As you can imagine, this can be quite expensive in terms of performance, so now you can see why it can be important to pay attention to what's in the Stack and Heap when trying to write high-performance code.
Ok... That great, but how does it really affect me?
Good question.
When we are using Reference Types, we're dealing with Pointers to the type, not the thing itself. When we're using Value Types, we're using the thing itself. Clear as mud, right?
Again, this is best described by example.
If we execute the following method:
public int ReturnValue()
{
int x = new int();
x = 3;
int y = new int();
y = x;
y = 4;
return x;
}
We'll get the value 3. Simple enough, right?
However, if we are using the MyInt class from before
public class MyInt
{
public int MyValue;
}
and we are executing the following method:
public int ReturnValue2()
{
MyInt x = new MyInt();
x.MyValue = 3;
MyInt y = new MyInt();
y = x;
y.MyValue = 4;
return x.MyValue;
}
What do we get?... 4!
Why?... How does x.MyValue get to be 4?... Take a look at what we're doing and see if it makes sense:
In the first example everything goes as planned:
public int ReturnValue()
{
int x = 3;
int y = x;
y = 4;
return x;
}

In the next example, we don't get "3" because of both variables "x" and "y" point to the same object in the Heap.
public int ReturnValue2()
{
MyInt x;
x.MyValue = 3;
MyInt y;
y = x;
y.MyValue = 4;
return x.MyValue;
}

Hopefully, this gives you a better understanding of a basic difference between Value Type and Reference Type variables in C# and a basic understanding of what a Pointer is and when it is used. In the next part of this series, we'll get further into memory management and specifically talk about method parameters.
For now...
Happy coding.
nan duPosted Jul 18, 2022, 2:31 AM
Hello, I have a question to ask you, why use heap as a data structure to store objects? without using graphs or other
Song HuiPosted Mar 28, 2022, 8:27 AM
Awesome clear, I have2 register and give it a thumb up! Wish that's a favorite button so i can keep this article in my acc, definitely my first choice if I need my junior to study on heap and stack
Gulshan KumarPosted Jan 21, 2022, 8:24 PM
Wow.. wonderful article .. cleared all confusion related memory allocation
M CPosted Jul 20, 2020, 2:13 PM
Thank you for this, it's really useful and has helped me to understand this concept. However, I'm confused about this method - public MyInt AddFive(int pValue). Since it returns a MyInt, when you call it, wouldn't you assign it to a new variable? So 'result' would be deleted from the stack, but a new reference would be created to the MyInt object instantiated inside the method?
Praneet RanePosted Mar 22, 2020, 9:34 PM
Thanks very detailed and nice post.I was looking for this information and came across this wonderful article.
Bohdan StupakPosted Feb 15, 2020, 11:42 AM
Really exhaustive guide
Opemipo OlugbengaPosted Jan 18, 2020, 7:18 AM
I really love the way you explained it. Best write up I have seen so far about stack and heap
Stephen BarrettPosted Sep 29, 2019, 7:38 PM
The beauty of pictures. If more stuff in coding was described through pictures, it would become waaaay more approachable to a wider audience. Great article.
Prerna ChaturvediPosted Apr 22, 2019, 7:48 AM
If a method have 2 parameters one is string and other is int.is still it go on stack?
Jakub SlonkaPosted Jan 12, 2019, 10:29 AM
Nice articIe which pretty much sums up the stack and heap. The only thing I would say is that I would be little more careful with the explanation about pointers. There is a slight difference between pointer and a reference. Pointer is unmanaged and only points to certain address in a memory, on the other hand reference points to the object and are managed by GarbageCollector. Reference can be moved around, but pointers are static.
Delton PhillipsPosted Jan 6, 2019, 10:45 PM
Well put together, I'm preparing training for some newbies at work and this is perfect for them... (and me)
Former memberPosted Dec 17, 2018, 7:50 AM
Very interesting description of Stack and Heap in C#. Keep it up.
pramod raisingPosted Nov 2, 2018, 4:16 AM
Very nice example of the Stack and heap memory
n uPosted Oct 25, 2018, 12:34 PM
Your second example returning MyInt is partially confusing. I think the GC cleaning up the referenced object on the heap may or may not clean it up depending upon if AddFive actually returned the object to another. For example, MyInt exampleRef = AddFive(10); In this case exampleRef is retaining the original object, at least until the scope it is running in finishes.
Hitanshi MehtaPosted Sep 25, 2018, 12:58 PM
Good one.Love it.
Sanjay YadavPosted Aug 13, 2018, 10:37 AM
Omg this is very awesome information thanks buddy.
Shailendra MishraPosted May 23, 2018, 12:18 AM
Informative & awesome......Big Thanks.
Chandana KolliPosted Apr 9, 2018, 1:11 PM
This is some super neat explanation... Thanks a bunch...
Shubham JainPosted Apr 2, 2018, 1:07 PM
This is an awesome article. A big thanks
sujeet kumarPosted Feb 3, 2018, 11:53 AM
Public MyInt AddFive(int pValue) { string str="test"; } In this str memory allocation will on stack or heap ??
Ronald AbellanoPosted Dec 21, 2017, 6:16 AM
This is way very explained and illustrated well. Thanks
Md Saud AlamPosted Sep 14, 2017, 1:06 AM
G00d explanation .. Full agree
PSiva RamPosted Sep 3, 2017, 2:00 PM
Superb explanation. Crystal clear really
Ponmani KannanPosted May 17, 2017, 3:32 AM
Very good explanation. Thank you
Jonathan ChapmanPosted May 16, 2017, 9:24 PM
In the last example, am I right in thinking there would actually be two MyInt on the heap; one pointed to by x and y and one orphaned but previously linked to by y?
Cong Hoang ThePosted Mar 16, 2017, 10:55 PM
I learn more knowledge in your article. Thank you!
Prakash TripathiPosted Mar 5, 2017, 8:50 AM
Appears to be simplistic explanation.
Mourad HasnaouiPosted Mar 3, 2017, 10:01 AM
Greate Article.. Thanks :)
Ramesh PalaniappanPosted Aug 19, 2016, 3:41 AM
Good one
Sharad GuptaPosted Jul 15, 2016, 1:23 AM
Good article sir@@ it clear many of doubt related to heap and stack thanks...
kalu singh raoPosted Jul 7, 2016, 8:40 AM
Nice...
SanPosted Jun 20, 2016, 7:01 AM
Nice one, well explained
Sourav BaruaPosted Jun 17, 2016, 7:57 AM
So far the best article about this concept...
Ganeshkumar LingappanPosted May 24, 2016, 9:08 AM
Great....... Nice Article
Thiruppathi RPosted May 22, 2016, 3:24 PM
Great...
Ashish SrivastavaPosted Apr 20, 2016, 11:48 AM
Nice
Rahul ChavanPosted Apr 7, 2016, 11:43 PM
I have a query- There are many objects in my heap and stack and memory is getting low. How Garbage Collector will come to know which object to recollect? Is there any property in object that tells GC that it can collect that object?
Syed Shujaat Hasnain AbdiPosted Mar 26, 2016, 10:19 AM
Good Elaboration....... it's really help me out............. Thank!
Rajesh Kumar MauryaPosted Mar 25, 2016, 3:40 AM
Superb...
Prakash TripathiPosted Mar 2, 2016, 12:39 PM
Nice explanation.
Harinder PrasadPosted Feb 25, 2016, 11:43 PM
excellent
Asfend YarPosted Feb 25, 2016, 4:25 PM
keep sharing
Asfend YarPosted Feb 25, 2016, 4:25 PM
very nice
Sonu ChaudharyPosted Feb 25, 2016, 6:30 AM
great
Muhammad BabarPosted Feb 23, 2016, 1:54 AM
Greattt................ Fabulous , Fantastic deserve 5 out of 5
Shailesh UkePosted Feb 16, 2016, 1:54 AM
Nice Article
Ehsan SajjadPosted Feb 11, 2016, 7:48 AM
very nice
KaustubhPosted Feb 3, 2016, 5:16 AM
nicely explained
Ashish SrivastavaPosted Jan 14, 2016, 5:56 AM
Good one
Rajeesh MenothPosted Nov 17, 2015, 1:08 AM
Nice One!
SharadPosted Jul 17, 2015, 3:39 AM
good one...
Rajendra TaradalePosted Jun 16, 2015, 4:38 AM
nice article
Abhijit KakadePosted Jun 3, 2015, 8:38 AM
Nice article with good presentation
Abhishek YadavPosted May 24, 2015, 11:59 PM
Awesome explanation + representation on 'STACK' and 'HEAP'.
S SPosted Dec 15, 2014, 8:16 AM
Wah...
Parmod KumarPosted Jan 9, 2014, 11:53 PM
Awesome...
karthik bodduPosted Aug 3, 2013, 9:50 PM
An excellent article keeping in mind the exact reader level-2. In detail, simple illustration to pass the message straight. Thank you very much !
Robert OschlerPosted Mar 26, 2013, 1:09 PM
Excellent article. Typo: "executin ghte method" -> "executing the method"
Anthony DeScenzoPosted Jun 15, 2012, 8:11 AM
Nevermind. I missed where you set y = x. Thank you. Great article!
Anthony DeScenzoPosted Jun 15, 2012, 8:02 AM
I am still not sure how you get to 4. You created 2 new instances of the class MyInt and set one instance (x) to 3 and the other (y) to 4. If you pass back x.MyValue which was set to 3, how do you transpose the value to y.MyValue. Also, in the second example, I am not sure how you would end up with 3 if they both pointed to the same object (this time with out the new keyword) because the last segment of code set the value to 4. Any help here would be great.
Rafiq ShahPosted May 27, 2012, 3:25 PM
Great article....
Rafiq ShahPosted May 27, 2012, 3:25 PM
Great article....
Rafiq ShahPosted May 27, 2012, 3:25 PM
Great article....
Rafiq ShahPosted May 27, 2012, 3:25 PM
Great article....
Rafiq ShahPosted May 27, 2012, 3:25 PM
Great article....
Sam HobbseditedPosted Jul 24, 2011, 6:57 PMEdited Jul 24, 2011, 6:58 PM
Thank you, Matthew. I first learned x86 assembler in about 1988 so I understand about stacks. I also can understand that stacks can be very confusing for beginners. I hope this helps beginners and obviously it does. I think one point that would help is to explain that the interneded purpose (at the machine level) of stacks is different from it's use in higher-level software such as C# and C++. At the assembler level, it is clear why it is called a stack; I think that the use of the stack in C# makes the meaning of "stack" as clear as mud, as you say.
Shivanand ArurPosted Jul 4, 2011, 3:43 AM
Hey Matthew, Thank you very much for posting this article... I honestly tell you that, i am a beginner in this programming field but after reading this article... many of my concepts which i was not understanding since a long time have been cleared... This is one of the best articles i have ever read... Once again thanks for posting. Regards, Shivanand Arur.
Raja BabuPosted Dec 4, 2010, 12:45 AM
is heap is pointer?
lorna mcneillPosted Nov 26, 2010, 5:12 AM
hi, sticking with the basics, can you explain what happens if this line is added to your example: MyInt j; does that allocate any memory (maybe just memory on the stack for a pointer/reference?)
Dave BlackPosted Oct 22, 2010, 12:06 PM
Reference and value types that are local variables can also be enregistered by the JIT and thus, technically, do not exist on either the Stack or the Heap; instead, they are placed into a CPU register for faster access. Whether or not a variable is enregistered is determined by the JIT at runtime and can only be performed if the assembly was compiled with optimizations turned on. A garbage collection is only triggered under 4 cases: When a memory allocation is requested and the GC determines that it does not have enough space available for the requested allocation. The *exact* algorithm for how this takes place is proprietary to Microsoft. However, high-level flowcharts about this process can be found on the internet. GC.Collect() is called - bad, bad, bad...don't ever do this! This should only be used for debugging scenarios. The GC "self-tunes" itself for collections while your app is running. This is based on how your app allocates memory and adjusts its collection algorithm accordingly. Once you call GC.Collect(), you basically "reset" the GC to start its tuning all over again! Memory pressure on the OS is detected. This does not mean memory pressure within your app. On a 32-bit process, you are limited to 2GB of virtual address space. Your app has to share this 2GB with CLR structures like memory for loading the CLR Types, GC stores some info there, and other memory taken by the OS for your app to run. By the time all is said and done, you have approximately 1.2GB for your memory allocations (this varies but not by much). Therefore, it is very easy to get an "OutOfMemoryException" even though you may have plenty of physical memory available. A "rude app domain unload" The important takeaway here is that your app may hold onto a huge amount of memory for an extended period of time until the next memory allocation request is made. Depending on your apps this could be seconds, minutes, hours, or days....
Akhil KumarPosted Oct 9, 2010, 1:49 PM
Hi.... I would like to know how the C# will decides that the variable will be created on the Stack or Heap. How its decides ?? Whether Its depends from where its derives System.ValueType or System.Object ???? Akhil
arun prasad sPosted Jul 8, 2010, 7:47 AM
Thanks for the good example with a clear pictorial representation
Veenu GoelPosted Jun 7, 2010, 6:36 AM
Hi Matthew! Can you please give me a basic idea about how the memory is configured with Stack and Heap, means is the Stack and Heap only the logical entities, or we can recognize while having a look at memory that where is stack and where is heap, and which is affecting the memory speed more??
john concessaoPosted May 14, 2010, 3:57 AM
This article gives a clear picture of Heap and stack in a simple way.I liked it.. Thanks Mathew
Luis AlavrezeditedPosted Feb 4, 2010, 5:57 PMEdited Feb 4, 2010, 5:58 PM
Thanks Matthew Cochran this is a great and well explained article. the drawings helps a lot to understand. Keep the good work!
TarikPosted Oct 15, 2009, 3:32 AM
Thanks for this really well-written article. It really helped me a lot maybe more than you was expecting during writing. Thanks...
Manish BhartiPosted Sep 12, 2009, 2:37 PM
Thanks Matthew very good article.
Jeff TannerPosted Aug 31, 2009, 5:15 PM
Hi Matthew Cochran, Is there a way to track specifically how much Stack-ing and Heap-ing is currently in use? I would like to checkout what is going on within the Stack and Heap (where, what, and how much memory) that is used during a specific event. Thanks
bala muruganPosted Jul 6, 2009, 8:12 AM
Hey its good.
Charanjot SinghPosted Jan 22, 2009, 6:18 AM
Thank you very much for giving such a wonderful and excellent explanation about Stack and Heap with examples. I didn't find such a health article about memory management. Thanks a lot....
PaulPosted Oct 7, 2008, 3:48 PM
It's nice to see this properly stated!
AnugraheditedPosted Jan 8, 2008, 1:43 AMEdited Jan 8, 2008, 1:45 AM
As you have said above that "all reference types are stored on heap except Sytem.Object myObject". Can you provide more details that why instance of class System.Object is not stored on Heap?
dakPosted Jan 4, 2007, 5:38 AM
In the example you have illustrated how does the control go to the AddFive method without popping out the pValue parameter(since pValue is @ the top of the stack)
srikanth reddyeditedPosted Oct 10, 2006, 2:04 AMEdited Dec 27, 2006, 1:09 AM
What is the DataRepeater,DataList,DataGrid what is the Main Difference between Both of us. Give me the brief explanation. if i use paging and adding controls to the dataRepeater
srikanth reddyeditedPosted Oct 10, 2006, 2:02 AMEdited Oct 30, 2006, 4:05 AM
What is the difference between Response.Redirect and server.Transfer Give me a detailed explanation.and give me the explanation about request.forms and request.QueryString
Matthew CochraneditedPosted Feb 12, 2006, 3:02 PMEdited Feb 12, 2006, 3:15 PM
This is a great question. It does get into territory a little deeper than I intended to go with this introductory article. To give a proper explaination of what is happening, I just wrote an article on boxing that deals with the situation you are running into that will go into more detail if you are interested. In brief, what's happening in your code sample is that the struct is being boxed when the delegate is created. When we execute the method via. the delegate we are really updating a copy of the object that was boxed to the Heap (we are no longer dealing with the object on the Stack). In the case when we use a class instead of the struct, the object lives on the Heap the whole time and we aren't dealing with two objects any more, so we get results more along the lines of what would be expected.
BeditedPosted Feb 8, 2006, 7:32 AMEdited Feb 14, 2006, 8:29 AM
I made a snippet of code that illustrates how a stuct handles delegates differently than a class. Run the code, then change the declaration 'public struct testStruct' to a class and you get the opposite result. Apparently, in a struct, test is stored by value instead of by reference, thus changes are lost. Any comment appreciated since I am still trying to make sense of this article: using System; namespace HeapVsStack { class HeapVsStack { delegate void aDelegate(); struct testBlock //DIFFERENT RESULT with: class testBlock { bool test; public testBlock(int x) { test = true; MakeTestFalseWithDelegate(new aDelegate(MakeTestFalse)); System.Console.ReadLine(); } void MakeTestFalse() { Console.WriteLine("Making test false"); test = false; } void MakeTestFalseWithDelegate(aDelegate adelegate) { adelegate(); Console.WriteLine("delegate result: " + test); } } static void Main(string[] args) { testBlock t = new testBlock(0); } } }