Hi! 👋
I finally decided to move away from all the meta-topics and C-stuff. As promised, I’m going to start exploring the .NET memory allocation and common data types.
If you’re a newcomer, this is article is a continuation of my Deep-dive into CLR (i.e. .NET’s runtime) series. If you haven’t seen any of the past articles - I’d recommend you start from beginning.
It’s really worth pointing out that if you’re not that familiar with Stacks and Heaps, I’d suggest reading this article to get a sense of it first. Additionally, you might benefit from going through the C++ and Memory Management series, which covers the basic concepts of memory works on a lower level.
As usual, the infographic goes first and then the more detailed text will be below:
For those in a real hurry, I guess it’s enough to remember that, when it comes to .NET and CLR, you really have two main data types - Values and References. Depending on who you ask, they might claim that “primitives” are a third type, but I’d just categorize them under Value Types. Value Types live on the Stack, and Reference Types are located on the Managed Heap. And, for those who want to continue with their day - that’s probably enough info.
For those eager to learn more - stay with me :) As we’ve discussed in the past articles, when it comes to Managed Code, it’s really the runtime engine (CLR) that determines where your data is stored. This is really interesting in comparison to C and C++, where you have the full control over the storage. As in, if you use the keyword “new” or “malloc”, your data will go to the (unmanaged) heap. On the other hand, if you just declare the variable, without “new” (or “malloc”), your data will be stored on the thread’s stack. So technically it’s up to you to decide where you want to place your data; and it’s also up to you to maintain the garbage left on the Heap.
In contrast, Managed Code has to manage the memory for you. And the language engineers seem to have thought that it’s a bit too much of a burden to bother you with, so they made a simple decision - any data type that inherits from System.ValueType (e.g. structs, enums, primitives like integers, floats, etc.) will be stored on the Stack. End of story. And this is probably something that would confuse a C++ engineer — the keyword “new” doesn’t allocate bits from the heap, but rather allocates the memory; on the stack; at least for Value Types.
When it comes to References, the story is different. Anything that is of “Reference” data type will ALWAYS go to the Heap. That includes Classes, Interfaces, Arrays, Strings, etc. Pretty much anything that could grow larger than couple of bytes is likely to go to Heap.
In a nutshell, and this is really amusing, when it comes to .NET and CLR - it’s the Data Type that determines where your data lives. And I think that’s just interesting :)
As usual, the devil really is in the details here. One with a sharp eye might notice and ask about Value Types inside Reference Types. For example - what happens with an Integer defined inside the Class? Does it live on the Stack or the Heap? And as you could imagine - answer is - obviously it lives on the Heap, because it’s part of the Reference Type. But these details and inner-workings is something that we will be discussing in more depth in future articles.
Before I close this off, I want to make honorable mention of “box” and “unbox”, which are some common concepts that many have heard of, but not everyone is comfortable elaborating. I’m in that group, but I’ll try to give a short intro - boxing variables referes to the process of converting them from Value to Reference type; or, as you could imagine, moving them from Stack to Heap. Unboxing, on the other hand, is kind of an opposite operation - it takes the Value Type from the Heap and stores it on the Stack. But as I’ve learned, there are one too many people pointing out that there’s much more than that, and this is really something that I’ll be exploring and writing about over next articles.
Finally, one last remark - there’s much more to be said about Values and References. One of their properties is where they are stored, but as many have pointed out - this is really more of an implementation detail. Still, I find this to be a valuable information, but in the next article I will dig into what they really are supposed to be.
Thanks for reading!
Other articles from the CLR series: