.NET memory management
Could someone provide a very high-level overview of .NET memory management?
More specifically I'm looking for an overview of memory managem开发者_运维知识库ent..
- is there an overall .net heap?
- are heaps application based?
- when I run my application is a new heap created/memory allocated or is the memory from the overal .net heap?
- what happens when the .net heap runs out of its original memory? does it request more from OS?
- the basics would be a great start for me to then go-on and read more
Each process has its own heap - and if more memory is needed after the GC has cleaned up everything it can, the process asks the OS for more information.
The best resource I know about for this sort of information is Jeffrey Richter's CLR via C# book.
is there an overall .net heap?
There are many. The ones you normally care about are the generation 0, 1 and 2 garbage collected heaps, the Large Object Heap and the loader heap. Generations help make the garbage collector more effective. The LOH is used for objects that are too large to move around. The loader heap stores static variable values.
are heaps application based?
No, they are AppDomain based. AppDomains provide a cheap alternative to a process.
when I run my application is a new heap created/memory allocated or is the memory from the overal .net heap?
The default CLR creates the primary AppDomain with its associated heaps before your code starts running.
what happens when the .net heap runs out of its original memory? does it request more from OS?
Yes.
I have covered the following questions in this article on .net memory management. I hope this gives readers a good idea of .net memory management.
- How memory is allocated to value types?
- How memory is allocated to reference types?
- How memory is allocated to static fields and global variables?
- How memory is allocated in multithreaded environment?
- How memory is allocated in inheritance?
- How GC works?
- What are Memory Management best practices?
Let us begin Memory allocation of .net types happens either in stack or heap. We need to understand when does a type be allocated in stack or heap.
STACK
All the local variables in a method are allocated memory in STACK. When a method A calls another method B, return address of calling method A is stored in STACK and the control is passed to method B. Once method B execution is complete, it is (along with its local data) removed from STACK and execution resumes from where it stopped in method A.
HEAP
Before we check what is stored in heap, we need to understand the root reference. Let us understand that using an example –
Let us say there is an employee class which contains list of employee skills. If we need to access the employee’s skills, we need create an object of employee class and then access that list.
So here object reference of type employee is the root reference which is stored on STACK and actual object is stored on heap
All global variables, static global variables and types (when initialized using new) are stored in a HEAP.
MEMORY ALLOCATION IN A MULTI-THREADED ENVIRONMENT Every thread has its own STACK, but HEAP is shared among all threads. So, it becomes important to ensure thread safety in case of HEAP because different threads can access/modify same resource.
Thread safety is out of scope in this document.
MEMORY ALLOCATION IN INHERITANCE When we create object of a child class, single object is created in heap. This object would hold all state related data of classes including the parent class.
GARBAGE COLLECTION (GC) .net uses garbage collection for automatic cleanup of allocated objects.
Garbage collector checks allocated objects on heap which are not referenced by anything or we may say which do not have a root reference.
Static Variables are allocated on heap and are never garbage collected because these never have root references.
GC runs on a separate thread for collecting the unused objects and free up memory. It runs automatically periodically or when application begins to run out of memory.
A developer can for GC to run by executing GC.Collect(), but it is not advisable to do so as it may hamper application performance.
GC GENERATIONS
Based on the object’s lifetime, it could be categorized into 3 categories –
Generation 0 – when the object is just created, it is put in Generation 0. It means this object is new and has not been checked by GC yet.
Generation 1 – object which is inspected by GC once, but survived because of having a root reference is put in Generation 1.
Generation 2 – objects which pass two or more inspections and are not killed by GC because of having a root reference are in Generation 2.
GC does not collect objects of unmanaged resources like file, network, database, UI elements. We need to use Dispose explicitly (IDisposable) or use the concerned class object within using statement (make sure IDiposable is inherited in the type we want to use dispose for).
MEMORY MANAGEMENT BEST PRACTICES
Use IDisposable or using statement to release unmanaged resources.
Try to defer the initialization of members of class if those are not required during creation of the class object.
Collections such as List sets the initial size to 4 elements if no size is defined during list creation. And if we add any element after 4, the collection size is doubled in memory. So, to avoid such situation and not take extra memory when list is small, it is recommended to specify the initial size of the collection.
Try to keep the data model simple and well structured. Because if it is too complex, GC would take more time in analyzing the whole graph to check which objects can be collected.
Make use of yield statement when possible. Yield keyword in C# is used to generate iterator pattern which is an IEnumerator implementation. The benefit of using yield statement is that the whole collection does not need to be in memory. It processes one item at a time.
Avoid excessive grouping or aggregate functions in LINQ queries.
THANK YOU!
精彩评论