46

I'm trying to learn how C# manages memory. I am stuck on static elements, I read numerous blogs and articles on this subject, but I cannot find a quite satisfactory answer.

Let's define a code block to help find the answer.

class myClass
{
    static string myStr = "String Data";
    static int myInt = 12;
}

Before you guys share your answer, let me share my findings that I know about this subject. Feel free to agree or disagree and help me to find correct answer.

  • Static is just for the lifetime.
  • A static reference type (myStr), will go on heap, for life time.
  • A static value type (myInt), will go on stack, for life time.

What confuses me, are some answers that I found on internet, on this subject.

Confusion Number 1:

When your program starts, it loads all the related assemblies into an AppDomain. When the assembly is loaded, all static constructors are called, including static fields. They will live in the there, and the only way to unload them, is to unload the AppDomain.

In above lines, it is mentioned explicitly that all static elements stored on AppDomain. Then why everybody on internet says 'Static' elements are stored on heap/stack?

Confusion Number 2:

Every static variable is stored on the heap, regardless of whether it's declared within a reference type or a value type.

If every static variable stored on heap. Then why some folks says that value type static variable are stored on stack?

Please help to connect my dots to understand memory management of static variables in C#. Thank you very much for your precious time :)

trincot
  • 317,000
  • 35
  • 244
  • 286
Ali Asad
  • 1,235
  • 1
  • 18
  • 33
  • 15
    People manage to confuse themselves hugely by dragging along the concepts of "stack" and "heap" in the first place. These concepts aren't useful in and of themselves if all you want to know about is the lifetime of an object or the scope of a declaration, which are far more relevant concepts in C#. Garbage collection means that, 95% of the time, all you need to care about is whether an object is live or not, and an object referenced by a `static` field is alive for as long as the class is loaded. (As to when it's instantiated, that's a more complicated topic.) Of course, this is not an answer. – Jeroen Mostert Jul 27 '16 at 11:57
  • 1
    Because they are mistaken. They know that value type _local_ variables are stored on the stack (when in fact all local variables are stored on the stack. The confusion is that for a reference type, the variable is the reference, not the object). Static variables are like members of the `Type` object, and `Type` is not a value type. (Of course, unlike Java, C# doesn't actually have a `Type` type to make it clearer that every `Type` is a _different_ type and has different members) – Random832 Jul 27 '16 at 20:49
  • 9
    @Random832: Not all local variables are on the stack. Closed over locals are not on the stack. Locals in iterator blocks are not on the stack. Locals in async methods are not on the stack. Enregistered locals are not on the stack. Elided locals are not on the stack. Stop believing that locals go on the stack; it's simply false. Locals are called locals *because their names have local scope*, not because they are stored on the stack. – Eric Lippert Jul 28 '16 at 05:42
  • @EricLippert I read your blog post. Your explanation is brilliant on truth of value types. Just one question if value type stores on heap, then it seems some boxing and unboxing is happening there? – Ali Asad Jul 28 '16 at 05:55
  • @AliAsad: Suppose you have an array of a thousand integers. Are those integers on the stack or the heap? Are they boxed or unboxed? – Eric Lippert Jul 28 '16 at 06:21
  • well its not a good idea to store them on stack. It should be on heap. if it is on heap then boxing is happening I suppose. – Ali Asad Jul 28 '16 at 06:43
  • 2
    @AliAsad: **Why** is boxing happening, do you suppose? What is boxing anyways? Your question indicates that you do not understand what boxing is; you think that "boxed" and "stored on the heap" mean the same thing, but they are not at all the same thing. It is helpful to me to understand why people believe completely false things about C#; why do you believe that "boxing" means "on the heap"? – Eric Lippert Jul 28 '16 at 18:27
  • @EricLippert, Please correct me then. Thanks :) – Ali Asad Jul 30 '16 at 10:01
  • @AliAsad: Start with: what is the difference between a *variable* and a *value*? Do you understand that difference? – Eric Lippert Aug 17 '16 at 13:43
  • yes i do. Variables are placeholders to store value – Ali Asad Aug 17 '16 at 14:42
  • @AliAsad: Variables are *storage locations* which store values, yes. Consider four kinds of variables used in a method: formals, locals, fields of a class, and array elements. `T M(T formal) { T local = new T(); local.field = new[] { formal }; return local; }` T is a class type. What are the *lifetimes* of each of the four *variables* with respect to the *activation of M*? – Eric Lippert Aug 23 '16 at 16:58

3 Answers3

64

First, note that all of this is an implementation detail. The only thing the runtime guarantees is:

  • When you ask for a static field, it's there
  • A static constructor is executed at some point before you use the type

That's pretty much it. Everything else is an implementation detail - the specification doesn't care about stack, heap or anything else. It's up to the implementation of the runtime, and a valid runtime could put everything on the stack, if it so desired, or on the heap. And don't forget registers.

Now, let's see some of the misconceptions you already managed to pick up:

  • Static is just for the lifetime - yes. It doesn't say anything about when or where it is stored - just that it's available when you asked for it. A compliant runtime is free to use whatever memory it wants, or even never to load the fields in memory (e.g. keeping it in the image, which is already in memory anyway)
  • Static will go on heap, for life time - most likely, yes. But it's not part of the specification, and a compliant runtime can store it wherever it wants, or nowhere at all, as long as the proper guarantees hold. Also, don't forget that "for life time" means "at least for the life time of the AppDomain"; it may or may not be released when the domain is unloaded.
  • Static value type will go on stack, for life time - most likely, no. Again, an implementation detail, but the stack has completely different semantics than what makes sense for a static value. And the next point will give you more of a reason why:
  • When the assambly is loaded, all static constructors are called, including static fields. - No. There is no such requirement, and no such guarantee. If you rely on this, your program is going to break (and I've seen that plenty of times before). Again, an implementation detail, but in the current MSCLR implementations, statics tend to be allocated in a heap of their own, and some time before the type they are defined in is needed. You can easily see this if you throw an exception in a static constructor - it will cause a TypeLoadException, most likely in a method that first references the type (needless to say, this can make debugging statics tricky).
  • Reference types go on the heap, value types go on the stack. - No. This is confusing the mechanism with the semantics. The only difference between the two are their semantics - everything else is up to the implementation. If a runtime can preserve reference semantics for reference types on the stack, that's perfectly valid. And even with current MSCLR runtimes, value types are stored on the heap all the time - whenever they are boxed, or members of a reference type, for example.

Some folks may be confused. Some don't understand the difference between the contract, and the practical implementations. Some simply don't know what they're talking about. I wish there was an easy way to know which is which, but there isn't. If in doubt, you can go to the C#/CLR specifications, but that only tells you about the contract, not the practical reality.

The whole point of managed memory is that you aren't supposed to care about these implementation details. Of course, like any abstraction, it leaks - and it makes sense to know how things really are, down to the CPU micro-intructions, memory caching etc., through all the various layers and abstractions. But it's nothing to rely on - the implementation can change at any time, and it has many times in the past.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • I agree with you that its all implementation detail which can change over time. So I conclude, AppDomain has its own static heap. Which manages static members of both value and reference type. – Ali Asad Jul 27 '16 at 13:31
  • @AliAsad Yeah, basically. It's still considered during garbage collection (it may have references to objects on other heaps), but not actually collected in practice. Also, note that strings are special - by default, all literal strings are interned, so if your statics have a string value, the value itself is likely in yet another heap (usually, the large object heap). – Luaan Jul 27 '16 at 13:58
  • @AliAsad And as for the contractual stuff, statics in different app domains are necessarily isolated. This doesn't *require* the objects to be in different heaps, but certainly makes it convenient :) – Luaan Jul 27 '16 at 14:02
  • @JanDvorak Yes, totally. Premature optimization hurts. But it's not just about micro-optimizations - it's a lot more about understanding tiny things like "should I arrange my 2D data row by row, or column by column?" Hide the decision behind an abstraction to keep the code clean and readable, but understand what matters under the abstraction as well. – Luaan Jul 27 '16 at 19:41
  • 3
    @Luaan. I did my little research on this subject. I found there are 8 types of heap. Two of them are **High Frequency Heap & Low Frequency Heap**. All static members lies in High Frequency Heap. The heap we use to store reference type objects is actually a Low Frequency Heap. For more info please visit [here](https://web.archive.org/web/20140724084944/http://msdn.microsoft.com/en-us/magazine/cc163791.aspx) and [here](https://vivekcek.wordpress.com/tag/stub-heap/) – Ali Asad Jul 28 '16 at 05:43
8

Whenever a process is loaded in the RAM, we can say that the memory is roughly divided into three areas (within that process): Stack, Heap, and Static (which, in .NET, is actually a special area inside Heap only known as High Frequency Heap).

The static part holds the “static” member variables and methods. What exactly is static? Those methods and variables which don't need an instance of a class to be created are defined as being static

Read more here.

Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
  • Note that this is just an article on CodeProject, with no references, no quotes from specification, no work from people designing or implementing .NET. It's a beginner introduction, and it's even obviously wrong (static methods are stored on the heap?). – Luaan Nov 21 '19 at 12:32
2

There is an instance of the class created, with all static members initialized.

Members of static classes are normally stored on the heap, members of value types are normally stored on the stack.

This doesn't have to be the case tho, you can read this blog for further information.

It is from one of the language designers from C#, Eric Lippert.

The blog shows that it's, contrary to normal knowledge, not sure that the value types are on the stack and reference types are on the heap, but they usually are.

It's just not specified in the specification.

Mafii
  • 7,227
  • 1
  • 35
  • 55