The CLR Garbage Collector divides Objects Based on the occupied space. The processing methods for large and small objects are quite different. For example, memory fragmentation-the cost of moving large objects in the memory is expensive. Let's look at how the Garbage Collector handles large objects and what potential impact large objects have on the procedure. Large Object heap and garbage collection are in. Net 1.0 and 2.0. If the size of an object exceeds 85000 bytes, this is considered a large object. This number is obtained based on performance optimization experience. When the applied memory size of an object reaches this threshold, it will be allocated to the large object stack. What does this mean? To understand this, we need to understand the. Net garbage collection mechanism. As most people know,. Net GC is recycled based on "Generation. The objects in the program have three generations: 0, 1, and 2. The 0 s are the youngest objects, and the 2 s have the longest survival time. GC garbage collection by generation is also out of performance considerations; normally, objects are recycled in the 0 generation. For example, in an asp.net program, all objects related to each request should be reclaimed at the end of the request. Objects that have not been recycled will become the first-generation object. That is to say, the first-generation object is a buffer between the resident memory object and the object that will soon die out. From the perspective of generation, a large object belongs to a two-generation object, because the large object is processed only when the two-generation object is recycled. When a generation of garbage collection is executed, the younger generation of garbage collection will be executed at the same time. For example, when the first generation of garbage collection is performed, both the first generation and the zero generation are recycled. When the second generation of garbage collection is performed, the first generation and the zero generation are recycled. instead, it is the logical view for the garbage collector to differentiate memory areas. From the perspective of physical storage, objects are allocated to different managed stacks. A managed heap is the memory area requested by the garbage collector from the operating system (by calling windows api VirtualAlloc ). When the CLR loads the memory, it initializes two managed heaps, one LOH-large object heap and one small object heap ). The memory allocation request puts the managed object on the corresponding managed stack. If the object size is less than 85000 bytes, It will be placed in SOH; otherwise it will be placed in LOH. For SOH, after a garbage collection is executed, the object enters the next generation. That is to say, if the first garbage collection is performed, the surviving object will enter the second generation. if the object is still not recycled as garbage after 2nd garbage collection, it will become a 2-generation object; the 2-generation object is the oldest object and will not be upgraded to algebra. When garbage collection is triggered, the garbage collector fragment the small object heap to move the surviving objects together. For large object heap, due to the high overhead of the mobile memory, the CLR team chooses to only clear them and form a list of recycled objects so that the memory can be applied for by large objects next time, adjacent junk objects are merged into idle memory blocks. It should always be noted that, until. Net 4.0 does not fragment large object heaps, and may do so in the future. Therefore, if you want to allocate large objects and do not want them to be moved, you can use the fixed statement. Reclaim The SOH of the following small object heap
(Click to view the big picture, the following similar) in the first garbage collection before there are four object obj0-3; after the first garbage collection obj1 and obj3 was recycled, while obj2 and obj0 moved together; three object obj4-6 were allocated before the second garbage collection; after the second garbage collection, obj2 and obj5 were reclaimed, and obj4 and obj6 were moved to the side of obj0. Is a large object heap LOH recycling can be seen before the garbage collection, a total of four object obj0-3; the first second generation of garbage collection after obj1 and obj2 was recycled, after the collection, the space occupied by obj1 and obj2 is merged. When obj4 applies for memory allocation, the space released after obj1 and obj2 are allocated to it; at the same time, a piece of memory fragmentation is left. If the size of the fragment is less than 85000 bytes, the fragment will never be reused in the life cycle of the program. If the large object stack does not have enough free memory to accommodate the large object space to be applied for, CLR first tries to apply for memory from the operating system. If the application fails, it will trigger a second generation recycle to try to release some memory. When two generations of garbage collection, you can return unnecessary memory to the operating system through VirtualFree. For details about the return process, see: When to recycle large objects? Before discussing how to recycle large objects, let's take a look at the timing of normal garbage collection operations. Garbage collection may occur in the following situations: 1. the requested space exceeds the 0-generation memory size or the threshold of a large object heap. In this case, most managed heap garbage collection occurs. call GC in program code. collect method; If GC is called. the Collect method is to pass in GC. when the MaxGeneration parameter is set, garbage collection is performed for all generation objects, including garbage collection for large object heaps. when the operating system memory is insufficient, when the application receives a high memory notification from the operating system 4. if the garbage collection algorithm determines that the second-generation garbage collection is effective, the second-generation garbage collection is triggered. each generation of object Heap has a space size threshold attribute. When you allocate objects to a generation, you increase the total memory size to the threshold of this generation, or, if the heap size of the current generation exceeds the heap threshold, a garbage collection occurs. Therefore, when you allocate a small object or a large object, it will consume a threshold of zero-generation heap or large object heap. When the Garbage Collector raises the object algebra to the first or second generation, it will consume the first and second generation threshold values. These thresholds dynamically change when the program is running. The impact of large object heap performance allows us to look at the cost of allocating large objects first. When the CLR allocates memory for each new object, it must ensure that the memory is cleared, which is not used by other objects (I give out is cleared ). This means that the allocation cost is completely controlled by the clearing cost (unless a garbage collection is triggered at the allocation ). If clearing 1 byte requires two cycles (cycles), it means that clearing a minimum large object requires 170,000 cycles. Normally, people do not allocate very large objects. For example, if a 16 m size object is allocated on a 2 GHz machine, it takes about 16 ms to clear the memory. This is too costly. Let's take a look at the cost of recycling. As mentioned above, large objects and 2 generations of age objects are recycled together. If the space occupied by a large object or a second-generation object exceeds the threshold, the second-generation object is recycled. If the two-generation object heap is triggered because the large object heap exceeds the threshold, there are not many objects in the two-generation object heap itself that can be recycled. If there are not many objects on the 2-generation stack, this is not a big problem. However, if there are many large objects in the 2-generation heap, excessive 2-generation recycling will cause performance problems. For temporary allocation of large objects, it takes a lot of time to run garbage collection. That is to say, if you continue to use large objects and then release large objects, it will have a great negative impact on performance. A huge object on a large object stack is usually an array (there is very few large objects ). If the elements in the object are strongly referenced, the cost is very high. If there is no mutual reference between elements, the whole array does not need to be traversed during garbage collection. For example, if you use an array to store a binary tree Node, You can strongly reference the left and right nodes in the Node: class Node {Data d; Node left; Node right ;} node [] binaryTree = new Node [num_nodes]; If num_nodes is a large number, it means that each Node needs to view at least two reference elements. An alternative solution is to save the array index number of the left and right Node elements in the Node class Node {Data d; uint left_index; uint right_index;} so that the reference relationship between the elements is removed; you can use binaryTree [left_index] to obtain the referenced node. The garbage collector does not need to look at reference elements when performing garbage collection. There are several ways to collect performance data for large object heaps. Before explaining these methods, let's talk about why we need to collect performance data related to large object heaps. When you start to collect performance data for a certain aspect, you may have found evidence of performance bottlenecks. Or you have not found any problems in all aspects. When looking for performance problems,. Net CLR Memory performance counters are usually the first tool to consider. The LOH-related counters include generation 2 collectioins (2-generation heap collection times) and large object heap size. Generation 2 collections shows the number of two generations of garbage collection operations after the process is started. The Large object heap size counter displays the size value of the current Large object heap, including the free space. This counter is updated after each garbage collection operation, not every memory allocation. For more information, see. Net CLR Memory performance data in windows performance counters.
You can also query the values of these counters through programs. Many people collect performance counters through programs to help find performance bottlenecks. You can also use the debugger winddbg to observe the large object heap. The last tip is: up to now, large object heaps are not organized by memory fragments as part of garbage collection, but this is just a detailed implementation of clr and the program code should not rely on this feature. To ensure that the object is not moved by the garbage collector, use the fixed statement.