Understanding Object Generations
Each object on the heap is assigned to a specific "generation". The idea behind generations is simple. The longer an object has existed on the heap, the more likely it is to stay there.
- Generation 0 : Identifies a newly allocated object that has never been marked for collection (with the exception of large objects, which are initially placed in a generation 2 collection). Most objects are reclaimed for gc in gen 0 and do now survive to gen 1.
- Generation 1 : Identifies an object that has survived a gc. This generation also serves as a buffer between short-lived objects and long-lived objects.
- Generation 2 : Identifies an object, that has survived more than one sweep of the gc or a significantly large object that started in a generation 2 collection.
Note: Gen 0 and 1 are termed ephemeral generations.
The gc will investigate all generation 0 objects first. If marking and sweeping these objects results in the required amount of free memory, any surviving objects are promoted to gen 1.
If all generation 0 objects have been evaluated but additional memory is still required generation 1 objects are then investigated for reachability and collected accordingly. Surviving gen 1 objects are then promoted to gen 2. If the gc still requires additional memory, gen 2 objects are evaluated. At this point, if a gen 2 object survives a gc, it remains a gen 2 object given the predefined upper limit of object given the predefined upper limit of objects generations.
The bottom line is that by assigning a generational value to objects on the heap, newer objects (such as local variables) will be removed quickly, while older objects (such as a program's main window) are not "bothered" as often.
GC is triggered when the system has low physical memory, when memory allocated on the managed heap rises above an acceptable threshold, or when GC.Collect() is called in the application code.
Ephemeral Generations and Segments
Gen 0 and 1 are short-lived and known ephemeral generations. These operations are allocated in a memory segment known as the ephemeral segments. As gc occurs, new segments acquired by the gc become new ephemeral segments, and the segment containing objects surviving past gen 1 becomes the new gen 2 segment.
Ephemeral Segments Sizes
| GC Type | 32-bit | 64-bit |
| Workstation | 16 MB | 256 MB |
| Server | 64 MB | 4 GB |
| Server - 4CPU | 32 MB | 2 GB |
| Server - 8CPU | 16 MB | 1 GB |
Garbage Collection Types
There are 2 types of gc provided by the runtime:
- Workstation Garbage Collection : This is designed for client applications and is the default for stand-alone applications. Workstation GC can be background or non-concurrent.
- Server Garbage Collection : This is designed for server applications that require high throughput and scalibility. Server GC can be background or nonconcurrent, just like workstation GC.
Note: The names are indicative of the default settings for workstation and server applications, but the method of gc is configurable through the machine's runtimeconfig.json or system environment variables. Unless the computer has only 1 processor, then it will always use workstation gc.
Workstating GC occurs on the same thread that triggered the gc and remains at the same priority as when it was triggered. This can cause competition with other threads in the application.
Server GC occurs on multiple dedicated threads that are set to THREAD_PRIORITY_HIGHEST priority level. Each CPU gets a dedicated heap and dedicated thread to perform gc. This can lead to server gc becoming ver resource intensive.
Background GC
The gc is able to deal with thread suspension when it cleans up objects on the managed heap, using background gc on the managed heap, using background gc. Despite its name, this does not mean that all gc now takes place on additional background threads of execution. Rather, if a background gc is taking place for objects living in a nonephemeral generation, the .NET Core runtime is now able to collect objects on the ephemeral generations using a dedicated background thread.
The System.GC Type
The mscorlib.dll assembly provides a class type named System.GC that allows you to programmatically interact with the gc using a set of static members. The only time you will use the members of System.GC is when you are creating classes that make internal use of unmanaged resources.
AddMemoryPressure() / RemoveMemoryPressure() : Allows you to specify a numerical value that represents the calling object's "urgency level" regarding the gc process. Be aware that these methods should alter pressure in tandem, and, thus, never remove more pressure than the total amount you have added.
- Collect() : Forces the GC to perform a gc.
- CollectionCount() : Returns a numerical value representing how many times a given generation has been swept.
- GetGeneration() : Returns the generation to which an object currently belong.
- GetTotalMemory() : Return the estimated amount of memory (in bytes) currently allocated on the managed heap.
- MaxGeneration : Returns the maximum number of generations supported on the target system.
- SuppressFinalize() : Sets a flag indicating that the specified object should not have its Finalize() method called.
- WaitForPendingFinalizers() : Suspends the current thread until all finalizable objects have been finalized. This method is typically called directly after invoking GC.Collect().
Console.WriteLine(GC.GetTotalMemory(false));
Console.WriteLine(GC.MaxGeneration+1);
Car c = new Car();
Console.WriteLine(GC.GetGeneration(c));
Forcing a Garbage Collection
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect(0); // GCCollectionMode
//
// Summary:
//Specifies the behavior for a forced garbage collection.
public enum GCCollectionMode
{
Default = 0,
Forced = 1,
Optimized = 2
}