04:30 Perhaps another explanation to the same thing: A value type is always on the "local memory frame" of its parent scope. In the application object type, it's the "local memory" of the object on the heap. In the method it's the "local memory" of the process, which is in this case the stack frame.
Please keep up the videos! I swear you put out videos, on specific topics I am currently learning, every single time. You have helped me push my skill set to the next level in many areas. Thank you very much.
Nice video. 0:25 The part of newly created reference type is the reference itself, which will be allocated on stack. So I think it is right to say that reference types will allocate memory on heap and stack.
Did anyone think that “value types are allocated on the stack” meant value types inside heap-allocated reference types? You only have to think about how objects are represented in memory to realize it can’t work that way.
Starting to watch video, preparing to be amazed to learn about some intricate details and exceptions to the rule, and then... Really? An int that's a field of a class is not on the stack? Really??!!! That's what you got? This is your argument for why people are wrong? Really?? ...ok, calming down now.
they are. Value type in a reference type (e.g member int) are maintained in the stack at all times. CLR maintains a “value-to-object-owner” dictionary that links the value type in the stack to the reference type that owns it. Now, when the current stack frame is removed, the value types in object instances are copied one level down the stack. That’s how copy-by-value semantics work. The value-to-owning-object dictionary is then updated. This explains why function calls are expensive. /s
That's interesting, I wouldn't have thought this distinction would need to be made. I've probably said the same thing before, but to me it's natural that the primitive components of reference types are stored on the heap (otherwise, what would "reference types are stored on the heap" even mean..?) I'm not incredibly knowledgeable about .NET internals, but I think local primitive types can also be register allocated as an optimization? It would make no sense if they couldn't. I suppose the only examples where you showed that they were on the stack required it because of pointers, so they probably can be.
Outstanding of all other reference types, an Array instance can be allocated on the stack by 'stackalloc' keyword and can be used by a pointer to its first element
The video contains good expertise on how the memory allocations is working in .NET tech. Btw, people aren't wrong about it. They "understand it" that any primitive type incapsulated into an object is a part of that object (like a package or frame) and is stored into heap. Thanks for interpolation investigation. I had not time to investigate its boxing behaviour. This is why I like the modern C#. Being a very high level coding language, it has many tools to control the memory in different scenarios.
I would add one more bullet. 6. Value type declared as a collection item (array, list, etc.) => Heap. This might be considered a special case of "member of class", but still.
Yeah this would fall under the member of class. Arrays were not inthe primitives list so it was implied that they are reference types which always go on the heap.
Excellently presented and articulated presentation of allocations on Stack vs Heap. Really cleared up my understanding of it. Keep up the excellent work.
Good explanation, but I kind of think that using it to say that the common phrase is 'wrong' is just a tiny bit pedantic. When people say 'reference types are allocated on the heap, value types on the stack' they still mean the behavior you describe, or at least they should. Otherwise, they would actually think that *everything* is allocated on the stack since all reference types are just compositions of value types (eg. primitives and pointers/references).
You'd be very surprised how many times I've got a wrong answer on this question. In 300 interviews, at least 150-160 candidates answer this wrong and when I give them this option to elaborate, they do say "always". So yeah, this is not about being pedantic but rather being accurate. It might be a no-brainer for you but it's be wrong in so many blogs that people just thnk it's how it is.
@@nickchapsas yes, it's about being pedantic. Stop conducting interviews and delegate it to someone competent. You are the worst type of interviewer. Nobody loves "Guess what I really meant to ask" and nobody thinks that classes are split into stack. By the way, you are very wrong. Reference types are not always allocated on the heap. Sometimes they are allocated in nowhere because system ran out of memory. If there is no heap - they are not allocated there. See how stupid it is?
Hmm, I've heard somewhere, that string interpolation is lowered to concatenation wherever it's possible, and string.format if it can't be simply concatenated in newer versions of dotnet
So it can actually be both. If you are dealing wiht strings then it will use string.Concat but if you have things that are not strings then it will use string.Format instead.
Dude, I had exactly the same argument/discussion about where value types are allocated, exactly on the same day you uploaded your video :). If I had known I would have sent your link and save a lot of time explaining :).
Well, I always view it like that: RefTypes live on the heap, ValueTypes prefer the stack, but will go on the heap if they are fields of something in the heap.
Super useful video! Thanks! BTW: you could assign shortcut for Line Move Up/Down.(f.e. in VS: Alt + up/down arrow. Minor thing, but very time saving :)
First of all, congratulations on all your videos, always interesting and very well explained. It would be nice if you can do some video on serverless architecture based on microservices, especially how to build a web API using Azure function and c#, integration with CosmosDb, strong authentication, best practices, tests, etc. It's just an idea, but I think it would be a very interesting series of videos.
"By supporting me with this tier you will gain access to the source code for all the videos published. There is currently no source code that is excluded from this tier but this might change in the future are I am planning to have a long running series on Microservices soon which might be on a different tier." - From Nick's patreon
I don't agree with your saying 'value types are sometimes allocated on the heap'. True is, their data will be nested between the object data on the heap but it won't get its own heap allocation: it will not have it's type nor a sync block index written together with it's data. Furthermore the garbage collector cannot free the value type instatiation independently from its holding object. So value types are not instantiated directly in the heap. They are also not always instantiated on the stack. They are instantiated within the scope of their creator. Can be some stack or heap memory.
I think, there is a default assumption is going on: “the question is related to allocating instances inside method call only”. I mean, I know about all of that things, but my answer was the wrong one in scope of your video
"int number = 420" ... I see what you did there hehe This is such a great practical explanation of the stack and heap, I feel most of the times when we are learning these abstract concepts there is a lack of concrete examples that help solidify the knowledge. Great job once again, Nick !
13:05 Could you please explain why the value-type properties doesn't appear in the instances? It must be allocated in the heap, but that non-appearance's confusing me. They're indeed wrappers on fields, but why don't we see the fields allocation? Is that a Rider's issue or what?
I am not a Rider user, and not viewing the values could be a bug, but I still need to correct you on "why don't we see the fields allocation". The whole point is that value types are in fact not allocated at all. You declare them in code for the compiler, but they do not exist as individual data blocks at runtime. Local stacks and reference types are the only thing actually being allocated (a location in memory is reserved, and the address of the start location is returned), simply with a size large enough to fit the values one by one inside them. The funny thing is that the reference types themselves hardly need any memory at all when they had no fields. It's really the value types that give them their size. The reference type instance itself just has an address number, which is 32 or 64 bit depending on your architecture.
Yes. Even inside the method when you define or declare an object there is a variable created on the stack that points to the memory on the heap that contains the object. So an object allocation can indeed mean 2 allocations: 1 in the stack: the variable holding the memory address, and 2 the object itself. To align with what Nick explained if that variable is actually a property of a class it will be a heap allocation pointing to a heap address.
@@nickchapsas That's pretty important though. Then there is concept of pooling and compacting which most developers dealing with LOH should know. Not knowing it might bite you both memory and performance wise
This seems a bit exaggerated. It's just easy to say value types are allocated on the stack and reference types on the heap as far as the call stack goes. That's not wrong. If you asked a somewhat experienced dev where are the fields on an instance are allocated, most would know it's on the heap. If it weren't, the heap would never be used.
It's been said wrong so many times that new developers take it for granted without knowing the context behind it. For you, an experienced dev, it might be a no brainer, but at least half the devs I've spoken to get it wrong.
From your intro statement I thought you would show an example where an object could be allocated on a stack. Sadly it's only possible in Java. edit: I wasn't listening good, Nick says that Ref-types are always on a heap.
@@Krokoklemmee When I told about Java i meant between .net and Java, as .net vas obviously made as MS Java, don't know if it is in other languages. And java has Escape Nalisis for ages. Go's escape analysis is a really different beast and it woks differently -- to move structs from stack to heap. When you say that it's possible not on;ly in java what do you mean? I do not recall a lot of managed languages. And I mean an automatic move from heap to stack in GC languages, not things like possible in C++ when user has full control of allocations. In java, JIT could perform analysis that value don't escape current thread and won't be stored in global variables, then it allocates Object in heap. Sadly it's not possible in dotnet, last time I've checked -- there was open issue on dontent-core repository. github.com/dotnet/runtime/issues/11192 But java lacks structs(AKA value types(they work on it, but really slowly)). Dotnet has structs and the possibility to allocate "arrays" of structs on the stack using *stackalloc* keyword. This is pretty useful, but hard to use. The addition of escape analysis would be great. P.S. en.wikipedia.org/wiki/Escape_analysis#Example_(Java) GO: medium.com/a-journey-with-go/go-introduction-to-the-escape-analysis-f7610174e890 in Go it's used when you pass a reference to variable into other function. The compiler can decide that this variable should live on heap, not stack.
Normally all kind of Arrays are also Reference Type and therefore allocated on the Heap. There is a struct Span though which, when used with stackalloc, can create an array on the stack: int [] myHeapArray = new int [100]; Span myStackArray = stackalloc int[10];
Obviously an int that's part of an object on heap will be on heap. People are not wrong when they say value types are on stack. If people have "discussions" about this, it's because they're talking past each other.
Don't points 3 and 4 at the end overlap? Couldn't you combine them and say, "A value type declared as a member is allocated with the parent? Can members be declared separately from their parents -- regardless of whether the parent is a class or struct?
4:10 how is that invalidate in reference types allocated on heap and value types allocated on the stack? number is part of the reference type, of course its on the heap and reference to that reference type is on stack btw stack is about code execution and heap is about storing stuff
IIRC, if it's stored on a reference type it goes on the heap, if it's created on a stack frame it goes on the stack. Keep in mind that the struct is created on a region (either stack or heap) but reference types always go on the heap. For example, assuming this struct A { object B; }; If you create A on a stack frame the struct itself is created on the stack but the reference type is created on the heap, you can see B as a "pointer" (it is not) so you store memory to store that "pointer" and the object itself resides on other memory region
@@alanramirezherrera7485 that's very interesting, thank you. So I guess the A wouldn't be cleaned from memory stack until B was collected from the heap? If I pass B around, would the framework clean A and keep B in the heap?
@@leonardoformaggi7614 no, A is freed when the stack gets destroyed but the reference type will be freed when the garbage collector reclaims memory, so, for example object Method() { var a = new A(); return a.B; } // A is freed when the method ends, a.B outlives this stack frame static void Main() { var b = Method(); } // when the garbage collector decides to reclaim memory and a.B is not referenced anymore, a.B gets freed
@@alanramirezherrera7485 thank you, that's very good to know because it's not always that a struct will have only value types and knowing when they will get destroyed is very useful.
It's very easy - the struct will be stored on the stack and will contain 64bit (depends on your OS bitness) value(pointer) which is the address of the object somewhere in the memory. It's very easy to demonstrate with some demo project and HxD)
Allocating a 4-Byte-Integer on the stack is a simple "add esp,4" for the cpu. Allocating the same integer on the Heap requires Heap Management to find a suitable place, note where and who accesses that integer and, finally, bother the GC with that Int.
In reality, most of the time, you shouldn't care. There is a real performance difference but it's only something to worry about if you've profiled your program and found an issue with allocations. It's still interesting and good to learn about though.
The difference is garbage collection and it's a pretty important one. Of course performance is contextual so it really comes down to the application itself. For 95% of all .NET apps you shouldn't care, but you should be aware because when it comes time to investigate a memory leak, understanding this stuff will be extremely helpful.
For example, if you want to implement a computational geometry algorithm in c#, using struct instead of a class you might notice some performance benefits. There are some general directions on when to use a struct but at the end all comes down to benchmarking, profiling and optimising the code.
So the main point is that if a valuetype is instantiated inside something on the heap, that it will be on the heap? Isn't that kinda obvious? I always understood the difference between struct and class in terms of C++ C# struct = "Foo foo{};" C# class = "Foo *foo = new Foo();" With Foo being either a class or struct (In C++ they are both the same, except for default access modifiers) With this understanding, it is obvious that a field of type "Foo" inside an object on the heap, will also be on the heap. I guess the only interesting part is the boxing topic, I didn't know that it would allocate everything twice. And the ref struct thing.
How about volatile keyword, does it only apply to value types? I just tested it for arrays and it didn't work out , you know the allocation of [i, j] over [j, i] , according to some pages [i, j] creates a block of data on cpu cache so that it's easier to retrieve data out of it but what if I use volatile int[N, N] , obviously there's something wrong with the theory.
So if ref struck is then used in the Console.WriteLine it will still be allocated on the heap because of boxing. Is that correct or have i misunderstood?
You can use dotpeek to generate PDBs from assemblies (it an external tool, not part of visual studio, in fact it is developed by JetBrains the same people behind rider) but you can then load the newly created external PDB symbols in Visual Studio. At one point people were developing an VS Plugin for this but haven't heard anything about it since the initial discussion. If your specifically interested only in the code that is part of the dot net framework, Microsoft is actually publishing their symbols online, you just need to enable the Microsoft symbols server from the debug options menu and uncheck the "Enable Just My Code" option. And in case you just want to look at the dot net source code you can find it here (also on github): referencesource.microsoft.com/
Visual Studio has .Net Object Allocation Tracing Feature, Shortcut : Alt + F2 , Menu => Debug ->Performance Profiler , and there are other options too , visual studio has many hidden features.
No, not in C#. At least you cannot enforce it. If you turn on "optimize code" they will be used heavily. To encourage it, you should have a short lifespan of local variables.
I think you're wrong. Yes, the statement 'Value types are always allocated on the stack' is misleading. Still, value types are never *allocated* on the heap! In your Application example, the int was never actually allocated at all. It was *stored* on the heap, but it didn't allocate that heap space. The space had already been allocated by the reference type (Application) and the value type just occupied this already allocated space. Also, when a value type is boxed, it is implicitly converted to a hidden reference type which contains the value type. You might not see the intermediate type, but it is definitely a reference type -- that is the whole point of boxing -- so there are still no value types being allocated on the heap. All that happens is that a reference type with a value typed field is allocated on the heap, which is exactly identical to your other example. If you actually allocate space for a value type by e.g. by binding it to a variable, then that space will *always* be allocated on the stack, so in a way the initial premise is technically not even wrong -- although it is a little misleading.
The fields of a reference type are allocated with their parent so yeah they are allocated on the heap. Not the stack. You can try that by trying to have a field that is a Span. You can’t because Spans can’t be allocated on the heap.
@@nickchapsas I think that @Prophet is correct here. When you instantiate a class, the allocator allocates a block of memory with respect to the size of the class. It doesn't care what the fields are. The class is allocated, not the fields. If you ignore templates and generics, the runtime doesn't care what the fields of a class are that all happens at compile time.
@@nickchapsas I may be wrong but I feel there's a difference. Value type will be stored on the heap as part of an instance of a class that contains this value type. But reference type could be stored as a reference to another place on the heap. Example: var someInstance = new SomeClass(); // space for Number property was allocated here. someInstance.Number = 5; // To assign value type we do not have to make any additional allocation someInstance.ReferenceTypeInstance = new OtherClass(); // We make another allocation here, ReferenceTypeInstance will be stored as a reference to newly allocated location on the heap So IMO saying that value types are allocated on the heap is a little bit confusing. But I can understand that people can think that it's literally stored on stack every single time, in that case I think they don't know what stack and heap are and they should taste some C programming language to learn ^^
👍🏽 “completely random number” picked. Lol
Needed to stay at 69 likes
@@jjxtra Or 420...
04:30 Perhaps another explanation to the same thing: A value type is always on the "local memory frame" of its parent scope. In the application object type, it's the "local memory" of the object on the heap. In the method it's the "local memory" of the process, which is in this case the stack frame.
Please keep up the videos! I swear you put out videos, on specific topics I am currently learning, every single time. You have helped me push my skill set to the next level in many areas. Thank you very much.
Nick Chapsas is a lowkey master of comedy
Nice video. 0:25 The part of newly created reference type is the reference itself, which will be allocated on stack. So I think it is right to say that reference types will allocate memory on heap and stack.
Did anyone think that “value types are allocated on the stack” meant value types inside heap-allocated reference types? You only have to think about how objects are represented in memory to realize it can’t work that way.
the video is clearly click-bait
@@khaimdecoster3867 +1
Starting to watch video, preparing to be amazed to learn about some intricate details and exceptions to the rule, and then... Really? An int that's a field of a class is not on the stack? Really??!!! That's what you got? This is your argument for why people are wrong? Really?? ...ok, calming down now.
Yeah, this is cringe-worthy.
they are. Value type in a reference type (e.g member int) are maintained in the stack at all times. CLR maintains a “value-to-object-owner” dictionary that links the value type in the stack to the reference type that owns it.
Now, when the current stack frame is removed, the value types in object instances are copied one level down the stack. That’s how copy-by-value semantics work. The value-to-owning-object dictionary is then updated. This explains why function calls are expensive.
/s
That's interesting, I wouldn't have thought this distinction would need to be made. I've probably said the same thing before, but to me it's natural that the primitive components of reference types are stored on the heap (otherwise, what would "reference types are stored on the heap" even mean..?)
I'm not incredibly knowledgeable about .NET internals, but I think local primitive types can also be register allocated as an optimization? It would make no sense if they couldn't. I suppose the only examples where you showed that they were on the stack required it because of pointers, so they probably can be.
Outstanding of all other reference types, an Array instance can be allocated on the stack by 'stackalloc' keyword and can be used by a pointer to its first element
The video contains good expertise on how the memory allocations is working in .NET tech. Btw, people aren't wrong about it. They "understand it" that any primitive type incapsulated into an object is a part of that object (like a package or frame) and is stored into heap. Thanks for interpolation investigation. I had not time to investigate its boxing behaviour.
This is why I like the modern C#. Being a very high level coding language, it has many tools to control the memory in different scenarios.
"boxing behaviour" heh, boxing 🥊
I would add one more bullet.
6. Value type declared as a collection item (array, list, etc.) => Heap.
This might be considered a special case of "member of class", but still.
Yeah this would fall under the member of class. Arrays were not inthe primitives list so it was implied that they are reference types which always go on the heap.
Except when you use stackalloc 😂
@@metaltyphoon Or using Span
Excellently presented and articulated presentation of allocations on Stack vs Heap. Really cleared up my understanding of it. Keep up the excellent work.
Very deep and clear explanation, extra thanks for conclusions in the end of the video
Good explanation, but I kind of think that using it to say that the common phrase is 'wrong' is just a tiny bit pedantic. When people say 'reference types are allocated on the heap, value types on the stack' they still mean the behavior you describe, or at least they should.
Otherwise, they would actually think that *everything* is allocated on the stack since all reference types are just compositions of value types (eg. primitives and pointers/references).
You'd be very surprised how many times I've got a wrong answer on this question. In 300 interviews, at least 150-160 candidates answer this wrong and when I give them this option to elaborate, they do say "always". So yeah, this is not about being pedantic but rather being accurate. It might be a no-brainer for you but it's be wrong in so many blogs that people just thnk it's how it is.
@@nickchapsas yes, it's about being pedantic. Stop conducting interviews and delegate it to someone competent. You are the worst type of interviewer. Nobody loves "Guess what I really meant to ask" and nobody thinks that classes are split into stack.
By the way, you are very wrong. Reference types are not always allocated on the heap. Sometimes they are allocated in nowhere because system ran out of memory. If there is no heap - they are not allocated there.
See how stupid it is?
Thank you for explaining... This highlighted a number of subtleties I didn't have a clear picture of. 👍
That was very useful. especially the wrap-up section at the end with the text. Thank you very much Nick
Very nice explanation and covers the nuances. Any plans to make a similar video on garbage collector?
Hmm, I've heard somewhere, that string interpolation is lowered to concatenation wherever it's possible, and string.format if it can't be simply concatenated in newer versions of dotnet
So it can actually be both. If you are dealing wiht strings then it will use string.Concat but if you have things that are not strings then it will use string.Format instead.
Watch @Shiv Kumar "string myth buster"
c# 10 will try to build it constant. It will even allow to use interpolations in constants, if they are constant (not format/culture-dependent)
In other words value types inherit or depend on their parent. And allocated in a scope or context of the parent.
Dude, I had exactly the same argument/discussion about where value types are allocated, exactly on the same day you uploaded your video :). If I had known I would have sent your link and save a lot of time explaining :).
Well, I always view it like that: RefTypes live on the heap, ValueTypes prefer the stack, but will go on the heap if they are fields of something in the heap.
Duuude! After almost every video I open IDE and try all that myself! This is awesome! Thanks for the HxD by the way
same situation
Rider Plugins -> Heap Allocations Viewer. It highlights most allocations in your code. That alone will save you a lot of trouble.
Super useful video! Thanks!
BTW: you could assign shortcut for Line Move Up/Down.(f.e. in VS: Alt + up/down arrow. Minor thing, but very time saving :)
I already use it. Im trying to minimise magic jumping around the files with keybindings because some people get confused.
again. One of the clearest and one of the best explanations on the subject.
Thats a video that totally blew my mind. Great effort. Thanks for putting this out, I will probably use it in my next interview!
Great.. This video given more information to beginners and experienced.
First of all, congratulations on all your videos, always interesting and very well explained.
It would be nice if you can do some video on serverless architecture based on microservices, especially how to build a web API using Azure function and c#, integration with CosmosDb, strong authentication, best practices, tests, etc.
It's just an idea, but I think it would be a very interesting series of videos.
"By supporting me with this tier you will gain access to the source code for all the videos published. There is currently no source code that is excluded from this tier but this might change in the future are I am planning to have a long running series on Microservices soon which might be on a different tier." - From Nick's patreon
@@volt4700 Thanks!
@@volt4700 Why on Earth would you want the exact source code used in the videos? It's literally just silly teaching examples.
You could have expanded a bit more on how to allocated buffers like byte or int Arrays on the stack with stackalloc
"Just another random number..." lolol
I don't agree with your saying 'value types are sometimes allocated on the heap'. True is, their data will be nested between the object data on the heap but it won't get its own heap allocation: it will not have it's type nor a sync block index written together with it's data. Furthermore the garbage collector cannot free the value type instatiation independently from its holding object.
So value types are not instantiated directly in the heap. They are also not always instantiated on the stack. They are instantiated within the scope of their creator. Can be some stack or heap memory.
Random numbers like 420 & 69 helped me understand the topic throughly. Thanks Nick.
Very good video. I don't have words how to thank you Nick!
Can you make a tutorial about pinning objects and how pinning works internally? (fixed operator)
pinning just prevents an object to be moved around by the garbage collector (the GC does that to avoid memory fragmentation)
Great video. just a small question. at 6:30 why there are 6 heap allocations. shouldnt it be 3?
@1:33
420 is my favorite random value!
I think, there is a default assumption is going on: “the question is related to allocating instances inside method call only”. I mean, I know about all of that things, but my answer was the wrong one in scope of your video
Premium topic + Premium explanation = thank you!
Could you explain what happens when a struct contains a class type members? How does the memory was allocated in this case?
When you applied string intrepolation to the value type ( 7:34 ) where there are two times the values are allocated?
This is shocking, my entire life was a lie.
Thanks for the great video, When the boxed int's get added to the heap why is each int being added twice vs once ?
"int number = 420" ... I see what you did there hehe This is such a great practical explanation of the stack and heap, I feel most of the times when we are learning these abstract concepts there is a lack of concrete examples that help solidify the knowledge. Great job once again, Nick !
13:05
Could you please explain why the value-type properties doesn't appear in the instances? It must be allocated in the heap, but that non-appearance's confusing me.
They're indeed wrappers on fields, but why don't we see the fields allocation? Is that a Rider's issue or what?
I am not a Rider user, and not viewing the values could be a bug, but I still need to correct you on "why don't we see the fields allocation".
The whole point is that value types are in fact not allocated at all. You declare them in code for the compiler, but they do not exist as individual data blocks at runtime.
Local stacks and reference types are the only thing actually being allocated (a location in memory is reserved, and the address of the start location is returned), simply with a size large enough to fit the values one by one inside them.
The funny thing is that the reference types themselves hardly need any memory at all when they had no fields. It's really the value types that give them their size.
The reference type instance itself just has an address number, which is 32 or 64 bit depending on your architecture.
HxD is a great program - used it for years. Great explanation, thanks.
You remember old OllyDbg? 😆
When passing a ref types to a method then pointer to it will be allocated on stack, is that right?🤔
Yes. Even inside the method when you define or declare an object there is a variable created on the stack that points to the memory on the heap that contains the object. So an object allocation can indeed mean 2 allocations: 1 in the stack: the variable holding the memory address, and 2 the object itself. To align with what Nick explained if that variable is actually a property of a class it will be a heap allocation pointing to a heap address.
waiting for SOH vs LOH allocation!
Oh that one would be going waaaaay too deep
@@nickchapsas That's pretty important though. Then there is concept of pooling and compacting which most developers dealing with LOH should know. Not knowing it might bite you both memory and performance wise
@@nickchapsas It's a good thing to be aware of! and we like it deep ;)
Thanks Nick helped a lot
This seems a bit exaggerated. It's just easy to say value types are allocated on the stack and reference types on the heap as far as the call stack goes. That's not wrong. If you asked a somewhat experienced dev where are the fields on an instance are allocated, most would know it's on the heap. If it weren't, the heap would never be used.
It's been said wrong so many times that new developers take it for granted without knowing the context behind it. For you, an experienced dev, it might be a no brainer, but at least half the devs I've spoken to get it wrong.
@@nickchapsas Good video regardless
This video shows why universities still start students with c++.
Where will the method arguments be located with modifiers ref, out, in ?
so variable is allocated in stack, but object which is ref stored in heap
Now the string interpolation avoid boxing for the value types
Thanks for sharing value information like this with us
What if a object be holded in a struct? It'll be allocated in heap or stack?
From your intro statement I thought you would show an example where an object could be allocated on a stack. Sadly it's only possible in Java.
edit: I wasn't listening good, Nick says that Ref-types are always on a heap.
who says that it's only possible in Java?
I'm not even sure if Java allows/does it, at least not that I've ever heard of
@@Krokoklemmee When I told about Java i meant between .net and Java, as .net vas obviously made as MS Java, don't know if it is in other languages. And java has Escape Nalisis for ages. Go's escape analysis is a really different beast and it woks differently -- to move structs from stack to heap. When you say that it's possible not on;ly in java what do you mean? I do not recall a lot of managed languages. And I mean an automatic move from heap to stack in GC languages, not things like possible in C++ when user has full control of allocations.
In java, JIT could perform analysis that value don't escape current thread and won't be stored in global variables, then it allocates Object in heap. Sadly it's not possible in dotnet, last time I've checked -- there was open issue on dontent-core repository. github.com/dotnet/runtime/issues/11192
But java lacks structs(AKA value types(they work on it, but really slowly)). Dotnet has structs and the possibility to allocate "arrays" of structs on the stack using *stackalloc* keyword. This is pretty useful, but hard to use. The addition of escape analysis would be great.
P.S. en.wikipedia.org/wiki/Escape_analysis#Example_(Java)
GO: medium.com/a-journey-with-go/go-introduction-to-the-escape-analysis-f7610174e890 in Go it's used when you pass a reference to variable into other function. The compiler can decide that this variable should live on heap, not stack.
Normally all kind of Arrays are also Reference Type and therefore allocated on the Heap. There is a struct Span though which, when used with stackalloc, can create an array on the stack:
int [] myHeapArray = new int [100];
Span myStackArray = stackalloc int[10];
What about static members of a class? Are they located on the heap?
Great session tq very much😊...
And referencetypes in a struct are stored in the heap, right?
Are `reference` types allocated on the heap or the stack?
How to view the tabs (Debugger - Console - Parallel stacks - Debug output - Memory ) showing in your VS
this actualy made a lot of sense
So the ref struct does not undergo boxing and unboxing in the string interpolation?
Obviously an int that's part of an object on heap will be on heap. People are not wrong when they say value types are on stack. If people have "discussions" about this, it's because they're talking past each other.
Might be obvious to you but I’ve heard the opposite from a lot of people
Don't points 3 and 4 at the end overlap? Couldn't you combine them and say, "A value type declared as a member is allocated with the parent?
Can members be declared separately from their parents -- regardless of whether the parent is a class or struct?
Thanks for the video!
What is your IDE ?
It’s called JetBrains Rider
4:10 how is that invalidate in reference types allocated on heap and value types allocated on the stack?
number is part of the reference type, of course its on the heap
and reference to that reference type is on stack btw
stack is about code execution and heap is about storing stuff
Excellent video! I just missed one topic, which is, structs with reference types as properties. Where do they go? I'd assume heap?
IIRC, if it's stored on a reference type it goes on the heap, if it's created on a stack frame it goes on the stack.
Keep in mind that the struct is created on a region (either stack or heap) but reference types always go on the heap.
For example, assuming this
struct A
{
object B;
};
If you create A on a stack frame the struct itself is created on the stack but the reference type is created on the heap, you can see B as a "pointer" (it is not) so you store memory to store that "pointer" and the object itself resides on other memory region
@@alanramirezherrera7485 that's very interesting, thank you. So I guess the A wouldn't be cleaned from memory stack until B was collected from the heap? If I pass B around, would the framework clean A and keep B in the heap?
@@leonardoformaggi7614 no, A is freed when the stack gets destroyed but the reference type will be freed when the garbage collector reclaims memory, so, for example
object Method()
{
var a = new A();
return a.B;
} // A is freed when the method ends, a.B outlives this stack frame
static void Main()
{
var b = Method();
} // when the garbage collector decides to reclaim memory and a.B is not referenced anymore, a.B gets freed
@@alanramirezherrera7485 thank you, that's very good to know because it's not always that a struct will have only value types and knowing when they will get destroyed is very useful.
It's very easy - the struct will be stored on the stack and will contain 64bit (depends on your OS bitness) value(pointer) which is the address of the object somewhere in the memory. It's very easy to demonstrate with some demo project and HxD)
dumb question... why should I care if its on the heap or the stack? whats the difference other than garbage collection?
Allocating a 4-Byte-Integer on the stack is a simple "add esp,4" for the cpu. Allocating the same integer on the Heap requires Heap Management to find a suitable place, note where and who accesses that integer and, finally, bother the GC with that Int.
In reality, most of the time, you shouldn't care. There is a real performance difference but it's only something to worry about if you've profiled your program and found an issue with allocations. It's still interesting and good to learn about though.
Depending on the type of applications you write, you shouldn't ever bother, or your life is going to depend on it. The former is far far more common.
The difference is garbage collection and it's a pretty important one. Of course performance is contextual so it really comes down to the application itself. For 95% of all .NET apps you shouldn't care, but you should be aware because when it comes time to investigate a memory leak, understanding this stuff will be extremely helpful.
For example, if you want to implement a computational geometry algorithm in c#, using struct instead of a class you might notice some performance benefits. There are some general directions on when to use a struct but at the end all comes down to benchmarking, profiling and optimising the code.
Is there a tool in Visual Studio that I can use to view the Heap variables (free tool - not ReSharper)?
Thank you! Very clear explanation)
So the main point is that if a valuetype is instantiated inside something on the heap, that it will be on the heap? Isn't that kinda obvious?
I always understood the difference between struct and class in terms of C++
C# struct = "Foo foo{};"
C# class = "Foo *foo = new Foo();"
With Foo being either a class or struct (In C++ they are both the same, except for default access modifiers)
With this understanding, it is obvious that a field of type "Foo" inside an object on the heap, will also be on the heap.
I guess the only interesting part is the boxing topic, I didn't know that it would allocate everything twice.
And the ref struct thing.
The dude is low budget Elon Musk over there with all the 69s and 420s :D but I adore your work, I've learned quite a bit just watching your videos.
8:48 Why were the day, month and year each allocated twice though?
How about volatile keyword, does it only apply to value types? I just tested it for arrays and it didn't work out , you know the allocation of [i, j] over [j, i] , according to some pages [i, j] creates a block of data on cpu cache so that it's easier to retrieve data out of it but what if I use volatile int[N, N] , obviously there's something wrong with the theory.
That's obvious, but it's better when you say it.
if reference type is member of value type then Where will reference type be located ?
Awesome info here 👍. Great job.
Thanks Nick. You are always so informative.
So if ref struck is then used in the Console.WriteLine it will still be allocated on the heap because of boxing. Is that correct or have i misunderstood?
yes
Subscribed twice
best explanation !
Which editor are you using?
JetBrains Rider
Is there a way to step into .net code (decompile) like how you did in rider in Visual Studio ?
Only if you are using Resharper
Yes there is experimental feature available in tools > options. However it might not be exactly the same.
You can use dotpeek to generate PDBs from assemblies (it an external tool, not part of visual studio, in fact it is developed by JetBrains the same people behind rider) but you can then load the newly created external PDB symbols in Visual Studio. At one point people were developing an VS Plugin for this but haven't heard anything about it since the initial discussion.
If your specifically interested only in the code that is part of the dot net framework, Microsoft is actually publishing their symbols online, you just need to enable the Microsoft symbols server from the debug options menu and uncheck the "Enable Just My Code" option.
And in case you just want to look at the dot net source code you can find it here (also on github): referencesource.microsoft.com/
Visual Studio has .Net Object Allocation Tracing Feature, Shortcut : Alt + F2 , Menu => Debug ->Performance Profiler , and there are other options too , visual studio has many hidden features.
What is this HzD tool he is using for viewing memory? Where can I download it? Google seems to know nothing about it
HxD
Great video, thanks.
What would happen if you had a struct with a reference type property (e.g. a List). Not saying that’s correct.
Are values types always allocated on stack/heap? Can value type not be allocated at all and be in registers?
Registers? Maybe some small values types that fits on register inside function could be allocated directly on register I guess.
No, not in C#. At least you cannot enforce it. If you turn on "optimize code" they will be used heavily. To encourage it, you should have a short lifespan of local variables.
Good to know.
ref structs: structs that are _never_ references. I always found that funny.
which IDE Nick is using. I can not find the Memory windows in Visual Studio 2022.
I'm using JetBrains Rider
@@nickchapsas Hello Nick! I did not expect the answer from you! I just want to say thanks so much for your awesome work! greeting from VietNam!
why did they call it 'ref struct' and not 'stack struct'?
this was gold
To allocate a value on the stack, do you need a stack!
I think you're wrong.
Yes, the statement 'Value types are always allocated on the stack' is misleading.
Still, value types are never *allocated* on the heap!
In your Application example, the int was never actually allocated at all. It was *stored* on the heap, but it didn't allocate that heap space. The space had already been allocated by the reference type (Application) and the value type just occupied this already allocated space.
Also, when a value type is boxed, it is implicitly converted to a hidden reference type which contains the value type. You might not see the intermediate type, but it is definitely a reference type -- that is the whole point of boxing -- so there are still no value types being allocated on the heap. All that happens is that a reference type with a value typed field is allocated on the heap, which is exactly identical to your other example.
If you actually allocate space for a value type by e.g. by binding it to a variable, then that space will *always* be allocated on the stack, so in a way the initial premise is technically not even wrong -- although it is a little misleading.
The fields of a reference type are allocated with their parent so yeah they are allocated on the heap. Not the stack. You can try that by trying to have a field that is a Span. You can’t because Spans can’t be allocated on the heap.
@@nickchapsas I think that @Prophet is correct here. When you instantiate a class, the allocator allocates a block of memory with respect to the size of the class. It doesn't care what the fields are. The class is allocated, not the fields. If you ignore templates and generics, the runtime doesn't care what the fields of a class are that all happens at compile time.
@@nickchapsas I may be wrong but I feel there's a difference. Value type will be stored on the heap as part of an instance of a class that contains this value type. But reference type could be stored as a reference to another place on the heap.
Example:
var someInstance = new SomeClass(); // space for Number property was allocated here.
someInstance.Number = 5; // To assign value type we do not have to make any additional allocation
someInstance.ReferenceTypeInstance = new OtherClass(); // We make another allocation here, ReferenceTypeInstance will be stored as a reference to newly allocated location on the heap
So IMO saying that value types are allocated on the heap is a little bit confusing. But I can understand that people can think that it's literally stored on stack every single time, in that case I think they don't know what stack and heap are and they should taste some C programming language to learn ^^
Sharing this for free
Kinda suprised that C# doesn't do value type string.format. Surely someone at .NET would have thought it would be a nice feature to have.
It internally uses stackalloc through ValueStringBuilder but the parameters need to be boxed no matter what.
nice content!!! ilove it
Very good 🎉
Nothing understandable for me, but very interesting))
Thank you