I have been tasked with sharing some of things I have learned about .NET applications and how they manage memory and sharing it with the team with intent of ensuring we are better prepared to investigate issues in production and that we are not creating new ones. Concepts like Garbage Collection (GC) exist to shield us from unnecessary complexity unfortunately in doing so it can mask ideas that are important.
For me, working with a high availability custom app server and IIS, healthy memory management is incredibly important, so delving below even good and robust abstractions is critical. I have spent the last few weeks looking for the right combination of videos, articles and topics to kick of this learning exercise. The first one is Everything you need to know about .NET memory by Ben Emmett.
I am encouraging my colleagues to start here, and after watching this video to consider and describe the following concepts:
- The function of the Stack and the Heap
- Describe Generational Garbage Collection
- Describe a GC root
- Some of the conditions that trigger a GC
- When and why objects get placed on the Large Object Heap (LOH).
- Describe how a Finalizer helps ensure we are clearing unmanaged resources.
General information about memory (below the .NET GC abstraction)
Each process has its own and separated virtual address space (we never manipulate physical memory directly), all processes on the machine share the same physical memory (plus the page file). The amount each process can access depends on the whether you are using a 32 or 64 bit machine. 4 GB (2GB user mode) for 32-bit Windows, 16 terabytes (8 terabytes user mode) for 64-bit Windows.
If you are writing managed code the GC is the one who allocates/frees virtual memory on your behalf. Even though this is handled for you, for the sake of speed, virtual address space can and will get fragmented, so it is possible and likely that you get free blocks between used address spaces, otherwise known as fragmentation.
Virtual memory can also be in different states:- free, reserved and committed.
- Free is … well free.
- Reserved is saying “I want to make this region of memory available for use later”. After reserving the space that block may not be used for other requests.
- You still cannot use reserved memory until it is committed. Committed memory has been paired up to the available physical memory so you can actually put data in it.
You can get out of memory if you are running out space to reserve, or space to commit. In the age of 64bit processors out of memory is most likely to mean unable to commit (out of physical memory rather virtual memory).