. Net garbage collection mechanism principle (2)

Source: Internet
Author: User

Weak References

When the root object of a program points to an object, the object is reachable, and the garbage collector cannot reclaim it. This is called a strong reference to the object. Relative to strong references is a weak reference. When a weak reference exists on an object, the garbage collector can reclaim the object, but it also allows the program to access the object. What is going on here? Please look down.

If there is only a weak reference on an object and the garbage collector is running, the object will be reclaimed, and if the object is accessed in the program, the access will fail. On the other hand, to use a weakly referenced object, the program must first strongly reference the object, if the program makes a strong reference to the object before the garbage collector reclaims the object, so (after a strong reference) the garbage collector This object cannot be recycled. This is a bit of a wander, let's use a piece of code to illustrate:

Void Method() {
/ / Create a strong reference to the object
Object o = new Object();
// weak reference with a weak reference object o.
WeakReference wr = new WeakReference(o);
 
o = null; // remove the strong reference to the object
 
o = wr.Target; //Try to get a strong reference to the object from the weak reference object
If (o == null) {
// If the object is empty, the object has been recycled by the garbage collector.
} else {
// If the garbage collector has not reclaimed this object, you can continue to use the object.
}
}
Why do you need weak objects? Because, some data is easy to create, but it requires a lot of memory. For example, you have a program that needs to access all the folders and file names on the user's hard disk; you can access the user disk to generate a data when the program first needs this data, and you can access the memory after the data is generated. Data to get user file data, rather than reading the disk every time to get data, this can improve the performance of the program.

The problem is that this data can be quite large and requires a lot of memory. If the user goes to operate another part of the program, this rather large amount of memory is not necessary. You can delete this data by code, but if the user immediately switches to the function that requires this piece of data, you must rebuild this data from the user's disk. Weak references provide a simple and effective solution for this scenario.

When the user switches to another function, you can create a weak reference object for this data and remove the strong reference to the data. In this way, if the memory occupied by the program is low, the garbage collection operation will not be triggered, and the weak reference object will not be recycled; thus, when the program needs to use the data, the data can be obtained through a strong reference. Object reference, the program does not need to read the user's disk again.

The WeakReference type provides two constructors:

WeakReference(object target);
WeakReference(object target, bool trackResurrection);
The target parameter is obviously a weak reference to the object to be tracked. The trackResurrection parameter indicates whether the object should be tracked after the object's Finalize method is executed. By default this parameter is false. Please refer to the resurrection of the object.

For convenience, a weak reference that does not track the resurrected object is called a "short weak reference"; a weak reference to track the resurrected object is called a "long weak reference." If the object does not implement the Finalize method, the long and weak references are exactly the same as the short and weak references. It is highly recommended that you avoid using long and weak references. Long and weak references allow you to use resurrected objects, and the behavior of resurrected objects may be unpredictable.

Once you have referenced an object using WeakReference, it is recommended that you set all of the object's strengths to null; if a strong reference exists, the garbage collector will never be able to reclaim the object pointed to by the weak reference.

When you want to use a weak reference target object, you must create a strong reference to the target object. This is very simple, just use object a = weekRefer.Target; you can then determine if a is empty, weak is not empty Can continue to use, weakly empty means that the object has been recycled by the garbage collector, you have to regain this object by other methods.


Internal implementation of weak references

From the description in the previous section, we can infer that the weak reference object is definitely not the same as the general object. In general, if an object references another object as a strong reference, the garbage collector cannot reclaim the referenced object, but the WeakReference object is not like this, and the object it references is likely to be recycled.

To fully understand how weak objects work, we also need to look at the managed heap. There are two internal data structures on the managed heap. Their only role is to manage weak references: we can refer to them as long weak reference tables and short weak reference tables; these two tables hold pointers to weak reference target objects on the managed heap.

At the beginning of the program, both tables are empty. When you create a WeakReference object, the object is not assigned to the managed heap, but an empty slot is created in the weak object table. The short weak reference object is placed in the short weak object table, and the long weak reference object is placed in the long weak reference table.

Once an empty slot is found, the value of the empty slot is set to the address of the weak reference target object; obviously the object in the long and weak object table is not considered to be the root object of the application. The garbage collector does not reclaim data from long and short weak object tables.

Let's see what happens when garbage collection is executed:
1. The garbage collector builds a reachable object graph. For the build steps, please refer to the above.
2. The garbage collector scans the weak object table. If the object pointed to in the weak object table is not in the reachable object graph, then the object is identified as a garbage object, and then the object pointer in the short object table is set to air
3. The garbage collector scans the final queue (refer to the above). If the object in the queue is not in the reachable object graph, the object moves from the final queue to the Freachable queue. At this time, the object is identified as a reachable object. No longer rubbish
4. The garbage collector scans the long weak reference table. If the object in the table is not in the reachable object graph (the object in the reachable object graph is included in the Freachable queue), set the corresponding object pointer in the long reference object table to null.
5. Garbage Collector Moves Reachable Objects

Once you understand the workings of the garbage collector, it's easy to understand how weak references work. Accessing the Target property of WeakReference causes the system to return the target object pointer in the weak object table. If it is null, the object has been recycled.

Short and weak references do not track resurrection, which means that the garbage collector can check if the object pointed to in the weak reference table is a garbage object before scanning the finalization queue.

The long and weak references track the resurrection object, which means that the garbage collector must set the pointer in the weak reference table to null after the acknowledgment object is reclaimed.

generation:

When it comes to .Net garbage collection, c++ or c programmers may think that there is no performance problem with managing memory. GC developers have been adjusting the garbage collector to improve its performance. Generation is a mechanism to reduce the impact of garbage collection on performance. The garbage collector will assume that the following statement is true at work:

1. The newer an object, the shorter the life cycle of the object
2. The older an object, the longer the life cycle of the object
3. There is usually a more likely relationship between new objects and new objects.
4. Compress a part of the heap faster than compressing the entire heap

Of course, a lot of research proves that the above assumptions are true in many procedures. Let us talk about how these assumptions affect the work of the garbage collector.

There are no objects on the managed heap when the program is initialized. At this time, the object newly added to the managed heap is 0. As shown in the following figure, the 0th generation object is the youngest object, and they have never been checked by the garbage collector.

Now if more objects are added to the heap, garbage collection will be triggered when the heap is full. When the garbage collector analyzes the managed heap, it constructs a garbage object (light purple block in Figure 2) and a non-garbage object. All objects that are not being recycled are compressed and compressed to the bottom of the heap. These objects that have not been recycled become the 1st generation object.


When more objects are allocated on the heap, the new object is placed in the 0th generation. If the 0 generation heap is full, a garbage collection will be triggered. At this time, the surviving object becomes the 1st generation object and is moved to the bottom of the heap; after the garbage collection, the surviving object in the 1st generation object is promoted to the 2nd generation object and is moved and compressed.


The 2nd generation object is the highest generation of the current garbage collector. When the garbage is recycled again, the algebra of the object that is not recycled remains 2.

Why can garbage recycling generation optimize performance?

As mentioned earlier, generational recycling can improve performance. Garbage collection is triggered when the heap is full, and the garbage collector can only select objects on generation 0 for recycling, ignoring objects on higher generation heaps. However, because the younger the object life cycle is, the recycling of the 0 generation heap can recover a considerable amount of memory, and the recovery consumes much less performance than recycling all generations.

This is the simplest optimization for generational garbage collection. Generational recycling does not need to facilitate the entire managed heap. If a root object references a high-generation object, the garbage collector can ignore the traversal of the high-generation object and its reference object, which greatly reduces the time to build the reachable object graph.

If the Reclaimed 0 generation object does not release enough memory, the garbage collector will try to reclaim the 1st and 0th generation heaps; if it still does not get enough memory, the garbage collector will try to reclaim the 2,1,0 generation heap. The algorithm that specifically recycles the generation of objects is not certain, and Microsoft will continue to do algorithm optimization.

Most heaps (like the c-runtime heap) are allocated to objects as long as they find enough free memory. Therefore, if I allocate multiple objects in succession, the address space of these objects may differ by a few M. However, on the managed heap, the memory addresses of consecutively allocated objects are contiguous.

It is also mentioned in the previous assumption that there is a greater possibility of mutual reference between new objects. So new objects are allocated to contiguous memory, and you can get performance gain from locality of reference. In this case, it is very likely that your objects are in the cache of the CPU, so that many operations of the CPU do not need to access the memory.

Microsoft's performance tests show that the managed heap is allocated faster than the standard win32 HeapAlloc method. These tests also show that a 200MHz Pentium CPU can do a 0 generation recovery time of less than 1 millisecond. Microsoft's optimization goal is to make garbage collection less time than a normal page fault.

Control garbage collection using the System.GC class

The type System.GC runtime developer directly controls the garbage collector. You can get the highest algebra of the GC through the GC.MaxGeneration property. The current highest generation is the fixed value 2.

You can call the GC.Collect() method to force the garbage collector to do garbage collection. The Collect method has two overloads:

Void GC.Collect(Int32 generation)
Void GC.Collect()
The first method allows you to specify which generation to recycle. You can pass 0 to the number of GC.MaxGeneration as a parameter, pass 0 to do the 0 generation heap recovery, pass 1 will recycle 1 generation and 0 generation heap, and pass 2 will recycle the entire managed heap. The parameterless method calls GC.Collect(GC.MaxGeneration), which is equivalent to the entire recycle.

Under normal circumstances, you should not call the GC.Collect method; it is best to let the garbage collector determine according to its own algorithm when to call the Collect method. Still, if you are sure that you know more about garbage collection when you are running, you can call the Collect method to do the recycling. For example, the program can do a garbage collection after saving the data file. For example, if your program just runs out of a large array of length 10000, you no longer need it, you can set it to null and then perform garbage collection to ease the memory pressure.

The GC also provides the WaitForPendingFinalizers method. This method simply suspends the execution thread, knows that after the emptying in the Freachable queue, it executes the Finalize method in all queues.

GC also provides two methods for returning an object to be several generations of objects, they are

Int32 GC.GetGeneration(object o);
Int32 GC.GetGeneration(WeakReference wr)
The first method returns a normal object for generations, and the second method returns the algebra of the weak reference object.

The following code can help you understand the meaning of the generation:

Private static void GenerationDemo() {
  // Let's see how many generations the GCH supports (we know it's 2)
  Display("Maximum GC generations: " + GC.MaxGeneration);
 
  // Create a new BaseObj in the heap
  GenObj obj = new GenObj("Generation");
 
  // Since this object is newly created, it should be in generation 0
  obj.DisplayGeneration(); // Displays 0
 
  // Performing a garbage collection promotes the object's generation
  GC.Collect();
  obj.DisplayGeneration(); // Displays 1
 
  GC.Collect();
  obj.DisplayGeneration(); // Displays 2
 
  GC.Collect();
  obj.DisplayGeneration(); // Displays 2 (max generation)
 
  Obj = null; // Destroy the strong reference to this object
 
  GC.Collect(0); // Collect objects in generation 0
  GC.WaitForPendingFinalizers(); // We should see nothing
 
  GC.Collect(1); // Collect objects in generation 1
  GC.WaitForPendingFinalizers(); // We should see nothing
 
  GC.Collect(2); // Same as Collect()
  GC.WaitForPendingFinalizers(); // Now, we should see the Finalize
  // method run
 
  Display(-1, "Demo stop: Understanding Generations.", 0);
}
Class GenObj{
  Public void DisplayGeneration(){
    Console.WriteLine("my generation is" + GC.GetGeneration(this));
  }
 
  ~GenObj(){
    Console.WriteLine("My Finalize method called");
  }
}
Multithreading performance optimization of garbage collection mechanism

In the previous section, I explained the algorithm and optimization of the GC, and then the premise of the discussion is in the single-threaded case. In a real program, it is likely that multiple threads work together, and multiple threads manipulate the objects on the managed heap together. When a thread triggers garbage collection, all other threads should suspend access to any referenced objects (including those referenced on their own stack) because the garbage collector may have to move the object and modify the object's memory address.

So when the garbage collector starts recycling, all threads that execute managed code must hang. There are several different mechanisms at runtime that can safely suspend threads to perform garbage collection. I don't intend to elaborate on the internal mechanism of this piece. But Microsoft will continue to modify the garbage collection mechanism to reduce the performance loss caused by garbage collection.

The following paragraphs describe how the garbage collector works in multithreading situations:
Completely interrupt code execution Hangs all application threads when garbage collection begins execution. The garbage collector then logs the location of the thread's hang to a table generated by a just-in-time (JIT) compiler, which is responsible for recording the location of the thread's hang in the table, recording the object that is currently being accessed. And where the object is stored (variables, CPU registers, etc.)
Hijacking: The garbage collector can modify the thread's stack to point the return address to a special method. When the currently executed method returns, this special method will execute and suspend the thread. This way of changing the thread execution path is called hijacking. Thread. When garbage collection is complete, the thread will return to the previously executed method.

Security Point: When the JIT compiler compiles a method, it can insert a piece of code at a certain point to determine whether the GC hangs. If so, the thread hangs waiting for garbage collection to complete, and then the thread restarts execution. The location where the JIT compiler inserts the check GC code is called the "safety point".

Note that thread hijacking allows threads that are executing unmanaged code to execute during the garbage collection process. This is fine if unmanaged code does not access objects on the managed heap. If this thread currently executes unmanaged code and then returns to execute managed code, the thread will be hijacked until garbage collection is complete.

In addition to the centralized mechanism I just mentioned, the garbage collector has other improvements to enhance object memory allocation and reclamation in multithreaded programs.

Synchronization-free Allocations: In a multi-threaded system, the 0-generation heap is divided into several regions, and one thread uses one region. This allows multiple threads to allocate objects at the same time, and does not require a thread to monopolize the heap.

Scalable Collections: The server version (MXSorSvr.dll) that runs the execution engine on a multi-threaded system. The managed heap is divided into several different areas, one CPU and one area. When recycling is initialized, each CPU executes a recycle thread, and each thread reclaims its own region. The workstation version of the execution engine (MXCorWks.dll) does not support this feature.

Large object recycling

This piece is not translated, there is a special article about this thing.

Monitor garbage collection

If you have the .Net framework installed in your .NET framework (Start Menu - Administrative Tools - Performance Entry) there will be a .Net CLR Memory item, you can select a program from the list of instances to observe.

The specific meanings of these performance indicators are as follows:

Performance counter

Description

# Bytes in all Heaps (number of bytes in all heaps)

The sum of the following counter values is displayed: the Level 0 Heap Size counter, the Level 1 Heap Size counter, the Level 2 Heap Size counter, and the Large Object Heap Size counter. This counter indicates the current memory (in bytes) allocated on the garbage collection heap.

# GC Handles(GC Processing Number)

Shows the current number of garbage collection processes in use. Garbage collection processing is the processing of resources outside the common language runtime and managed environments.

# Gen 0 Collections (Level 2 Recycling Times)

Shows the number of times the level 0 object (that is, the youngest, most recently assigned object) was garbage collected since the application started.

Level 0 garbage collection occurs when there is not enough free memory in level 0 to satisfy the allocation request. This counter is incremented at the end of level 0 garbage collection. Higher level garbage collection includes all lower level garbage collection. This counter is explicitly incremented when a higher level (level 1 or level 2) garbage collection occurs.

This counter shows the most recent observed value. The _Global_ counter value is not accurate and should be ignored.

# Gen 1 Collections (Level 2 Recycles)

Shows the number of garbage collections of Level 1 objects since the application started.

This counter is incremented at the end of level 1 garbage collection. Higher level garbage collection includes all lower level garbage collection. This counter is explicitly incremented when higher level (level 2) garbage collection occurs.

This counter shows the most recent observed value. The _Global_ counter value is not accurate and should be ignored.

# Gen 2 Collections (Level 2 Recycling Times)

Shows the number of times that a Level 2 object was garbage collected since the application started. This counter is incremented at the end of level 2 garbage collection (also known as full garbage collection).

This counter shows the most recent observed value. The _Global_ counter value is not accurate and should be ignored.

# Induced GC (Number of GCs Raised)

Shows the peak number of garbage collections that were performed due to an explicit call to GC.Collect. It is practical to let the garbage collector fine-tune the frequency of its recycling.

# of Pinned Objects (number of objects pinned)

Shows the number of pinned objects encountered in the last garbage collection. Pinned objects are objects that the garbage collector cannot move into memory. This counter only tracks pinned objects in the heap being garbage collected. For example, level 0 garbage collection causes only the objects pinned in the level 0 heap to be enumerated.

# of Sink Blocks in use (number of receiving blocks in use)

Shows the current number of sync blocks in use. A sync block is an object-based data structure that is allocated for storing synchronization information. The sync block retains a weak reference to the managed object and must be scanned by the garbage collector. Synchronization blocks are not limited to storing only synchronization information; they can also store COM interop metadata. This counter indicates performance issues related to excessive use of synchronization primitives.

# Total committed Bytes (total number of committed bytes)

Shows the amount of virtual memory (in bytes) currently submitted by the garbage collector. The committed memory is the physical memory of the space reserved in the disk page file.

# Total reserved Bytes (total number of reserved bytes)

Shows the amount of virtual memory (in bytes) currently held by the garbage collector. Reserved memory is the virtual memory space reserved for the application (but not using any disk or main memory pages).

% Time in GC (% of time in GC)

Shows the percentage of runtime used to perform garbage collection since the last garbage collection cycle. This counter typically indicates what the garbage collector does on behalf of the application to collect and compress memory. This counter is only updated at the end of each garbage collection. This counter is not an average; its value reflects the most recently observed value.

Allocated Bytes/second (number of bytes allocated per second)

Shows the number of bytes allocated on the garbage collection heap per second. This counter is updated each time garbage collection ends (rather than at each allocation). This counter is not an average over time; it shows the difference between the values observed in the last two samples divided by the sampling interval.

Finalization Survivors (number of objects persisted at completion)

Shows the number of objects that were garbage collected after being recycled because they are waiting for completion. If these objects retain references to other objects, those objects are also preserved, but this counter does not count them. The "Complete Memory from Level 0 Upgrade" and "Complete Memory from Level 1" counters represent all memory that was retained due to completion.

This counter is not an accumulation counter; it is updated by the count of objects that are only persisted during that particular collection period at the end of each garbage collection. This counter indicates that the system overhead may be too high due to the completion of the application.

Gen 0 heap size (Level 2 heap size)

Shows the maximum number of bytes that can be allocated in level 0; it does not indicate the number of bytes currently allocated in level 0.

Level 0 garbage collection occurs when the allocation since the most recent reclamation exceeds this size. Level 0 is fine-tuned by the garbage collector and can be changed during application execution. At the end of level 0 reclamation, the size of the level 0 heap is 0 bytes. This counter shows the size, in bytes, of the allocation that called the next level 0 garbage collection.

This counter is updated at the end of garbage collection (rather than at each allocation).

Gen 0 Promoted Bytes/Sec (bytes/seconds boosted from level 1)

Shows the number of bytes raised from level 0 to level 1 per second. Memory is promoted after it has been retained from garbage collection. This counter is an indicator of objects that are created per second that are retained for a relatively long time.

This counter shows the difference between the values observed in the last two samples (divided by the sampling interval duration).

Gen 1 heap size (Level 2 heap size)

Displays the current number of bytes in level 1; this counter does not display the maximum size of level 1. Objects are not allocated directly in this generation; these objects are promoted from the previous level 0 garbage collection. This counter is updated at the end of garbage collection (rather than at each allocation).

Gen 1 Promoted Bytes/Sec (bytes/seconds boosted from level 1)

Shows the number of bytes per second from level 1 to level 2. Objects that are only promoted because they are waiting for completion are not included in this counter.

Memory is promoted after it has been retained from garbage collection. No promotion will be made from level 2 because it is the oldest level. This counter is an indicator of the object that is created for a very long time that is created every second.

This counter shows the difference between the values observed in the last two samples (divided by the sampling interval duration).

Gen 2 heap size (Level 2 heap size)

Displays the current number of bytes in level 2. Objects are not allocated directly in this generation; they are promoted from level 1 during the previous level 1 garbage collection. This counter is updated at the end of garbage collection (rather than at each allocation).

Large Object Heap size

Displays the current size of the large object heap in bytes. The garbage collector treats objects larger than 20 KB as large objects and directly allocates large objects in special heaps; they are not promoted by these levels. This counter is updated at the end of garbage collection (rather than at each allocation).

Promoted Finalization-Memory from Gen 0 (completed memory from level 1)

Shows the number of bytes of memory that was promoted from level 0 to level 1 only due to waiting for completion. This counter is not an accumulation counter; it shows the value observed at the end of the last garbage collection.

Promoted Finalization-Memory from Gen 1 (completed memory from level 1)

Shows the number of bytes of memory that was promoted from level 1 to level 2 only due to waiting for completion. This counter is not an accumulation counter; it shows the value observed at the end of the last garbage collection. This counter is reset to 0 if the last garbage collection is level 0 reclamation.

Promoted Memory from Gen 0 (memory boosted from level 1)

Shows the number of bytes of memory that have been retained since garbage collection and promoted from level 0 to level 1. Objects that are only promoted by waiting for completion are not included in this counter. This counter is not an accumulation counter; it shows the value observed at the end of the last garbage collection.

Promoted Memory from Gen 1 (memory boosted from level 1)

Shows the number of bytes of memory that have been retained since garbage collection and promoted from level 1 to level 2. Objects that are only promoted by waiting for completion are not included in this counter. This counter is not an accumulation counter; it shows the value observed at the end of the last garbage collection. This counter is reset to 0 if the last garbage collection is level 0 reclamation.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.