In your actual programming experience, how did this knowledge of STACK and HEAP actually rescue you in real life? Any story from the trenches? Or is this concept good for filling up programming books and good for theory?
To me it is the difference between being a "developer/programmer" and a "craftsman". Anyone can learn to write code and see how things just "magically happen" for you not knowing why/how. To really be valuable at what you do, I think there is a great importance to find out as much as you can about the Framework you're using. Remember it's not just a language, it's a Framework that you leverage to create the best application to your abilities.
I've analyzed many memory dumps over the years and found it extremely helpful knowing the internals and differences between the two. Most of these have been OutOfMemory conditions and unstable applications. This knowledge is absolutely necessary to use WinDbg when looking at dumps. When investigating a memory dump, knowing how memory is allocated between the kernel/user-mode process and the CLR can at least tell you where to begin your analysis.
For example, let's take an OOM case: The allocated memory you see in the Heap Sizes, Working Set, Private Memory, Shared Memory, Virtual Memory, Committed Memory, Handles, and Threads can be a big indicator of where to start.
There about 8 different heaps that the CLR uses:
- Loader Heap: contains CLR structures and the type system
- High Frequency Heap: statics, MethodTables, FieldDescs, interface map
- Low Frequency Heap: EEClass, ClassLoader and lookup tables
- Stub Heap: stubs for CAS, COM wrappers, P/Invoke
- Large Object Heap: memory allocations that require more than 85k bytes
- GC Heap: user allocated heap memory private to the app
- JIT Code Heap: memory allocated by mscoreee (Execution Engine) and the JIT compiler for managed code
- Process/Base Heap: interop/unmanaged allocations, native memory, etc
Finding what heap has high allocations can tell me if I have memory fragmentation, managed memory leaks, interop/unmanaged leaks, etc.
Knowing that you have 1MB (on x86)/ 4MB (on x64) of stack space allocated for each thread that your app uses reminds me that if I have 100 threads you will have an additional 100MB of virtual memory usage.
I had a client that had Citrix servers crashing with OutOfMemory problems, being unstable, slow responsiveness when their app was running on it in multiple sessions. After looking at the dump (I didn't have access to the server), I saw that there were over 700 threads being used by that instance of the app! Knowing the thread stack allocation, allowed me to correlate the OOMs were caused by the high thread usage.
In short, because of what I do for my "role", it is invaluable knowledge to have. Of course even if you're not debugging memory dumps it never hurts either!
Personally, this is one of the very few technical questions that I ask every person I'm going to hire.
I feel that it is critical to understanding how to use the .NET framework (and most other languages). I never hire somebody who doesn't have a clear understanding of memory usage on the stack vs. the heap.
Without understanding this, it's almost impossible to understand the garbage collector, understand .NET performance characteristics, and many other critical development issues.
The distinction in .NET between the semantics of reference types and value types, is a much more important concept to grasp.
Personally, I have never bothered thinking about the stack or heap in all my years of coding (just CLR based).
I don't think it matters if you're just building average business applications, which I think most .NET programmers are.
The books I've seen just mention stack and heap in passing as if memorizing this fact is something of monumental importance.
It certainly is helpful to understand the distinction when one is building compilers.
Here are a few articles I've written about how various issues in memory management impact the design and implementation of the C# language and the CLR:
We had a Claim Entity (business Object) which contained data for an entire claim. One of the requirements of the application was to create an audit trail of every single value changed by the user. In order to this without hitting the database twice we would maintain Original Claim Entity in the form and a Working Claim Entity. The Working Claim Entity would get updated when the user clicked Save and we would then compare the Original Claim Entity properties with corresponding Working Claim Entity properties to determine what changed. One day we noticed hey our compare method is never finding a difference. This is where my understanding of the Stack and Heap saved my rear end (specifically value types vs reference types). Because we needed to maintain to copies of the same object in memory the developer simply created two objects
Dim originalClaim As ClaimBE Dim workingClaim As ClaimBE
then called the business layer method to return the claim object and assigned the same claimBE to both variables
originalClaim = BLL.GetClaim() workingClaim = originalClaim
hence two reference types pointing to the same value type. Nightmare averted.