Home >Backend Development >C#.Net Tutorial >Detailed introduction to the garbage collection mechanism of Java and C#
(1) Basic assumptions of the garbage collector
(1) Objects that have recently been allocated memory space are most likely to need to be released. Before a method is executed, it is usually necessary to allocate memory space for the objects used by the method. Searching the collection of recently allocated objects can help free up as much free memory space as possible with the least amount of work.
(2) The object with the longest life span is the least likely to need to be released. Objects that still exist after several rounds of garbage collection are unlikely to be temporary objects that can be released in the next round of garbage collection. Searching these memory blocks often requires a lot of work, but only a small part of the memory space can be released. .
(3) Objects that allocate memory at the same time are usually used at the same time. Connecting object storage locations that allocate memory at the same time to each other can help improve cache performance.
(2) Several garbage collection mechanisms
(1) Mark-clear collector
This type of collector first traverses the object graph and marks reachable objects, then scans the stack for unmarked objects and frees their memory. This type of collector generally uses a single thread to work and stops other operations.
(2) Mark-Compact Collector
Sometimes also called Mark-Sweep-Compact Collector, which is different from Mark-Sweep Collector Same marking phase. In the second phase, the marked object is copied to a new area of the stack in order to compress the stack. This collector also stops other operations.
(3) Copying collector
This collector divides the stack into two domains, often called half space. Only half of the space is used each time, and new objects generated by the jvm are placed in the other half of the space. When gc runs, it copies reachable objects to the other half of the space, thus compressing the stack. This method is suitable for short-lived objects. Continuous copying of long-lived objects will lead to reduced efficiency.
(4) Incremental collector
The incremental collector divides the stack into multiple domains and only collects from one domain at a time Rubbish. This causes minor application disruption.
(5) Generational collector
This collector divides the stack into two or more domains to store different Lifespan object. New objects generated by jvm are generally placed in one of the fields. Over time, the surviving objects will acquire a useful life and be transferred to a longer-lived domain. Generational collectors use different algorithms for different domains to optimize performance.
(6) Concurrent collector
The concurrent collector runs at the same time as the application. These collectors generally have to stop other operations at some point (such as compaction) to complete a specific task, but because other applications can perform other background operations, the actual time to interrupt other processing is greatly reduced.
(7) Parallel collector
Parallel collectors use a certain traditional algorithm and use multiple threads to perform their work in parallel. Using multi-threading technology on multi-CPU machines can significantly improve the scalability of Java applications.
(3) .NET Framework Garbage Collection Mechanism
## .NET Framework contains a managed heap, all. NET language uses it when allocating reference type objects. Lightweight objects like value types are always allocated on the stack, but all class instances and arrays are generated in a memory pool, which is the managed heap.
The garbage collector in the .NET framework is called a generational garbage collector (Generational Garbage Collector), which means that the allocated objects are divided into three categories, or For "generation". They are 0, 1, and 2 respectively. The initial sizes of the managed heaps corresponding to generations 0, 1, and 2 are 256K, 2M, and 10M respectively. The garbage collector will change the size of the managed heap if it finds that changing the size will improve performance. For example, when an application initializes many small objects, and these objects will be recycled quickly, the garbage collector will increase the managed heap in generation 0 to 128K and increase the frequency of recycling. If the situation is reversed, and the garbage collector finds that it cannot reclaim much space in the managed heap in generation 0, it will increase the managed heap size. All levels of the managed heap are empty until the application is initialized. When objects are initialized, they are placed into the managed heap in generation 0 in the order in which they were initialized.
Objects that have recently been allocated memory space are placed in generation 0. Because generation 0 is small, small enough to fit into the processor's second level (L2) cache, generation 0 can provide us with Quick access to objects within it. After a round of garbage collection, objects still in generation 0 are moved into generation 1. After another round of garbage collection, objects still in generation 1 are moved into generation 2. . Generation 2 contains long-lived objects that have gone through at least two rounds of collection.
When a C# program allocates memory for an object, the managed heap can almost immediately return the memory required for the new object. The reason why the managed heap can have such efficient memory allocation performance is because the managed heap A relatively simple data structure. The managed heap is similar to a simple byte array, with a pointer to the first available memory space.
When a block is requested by an object, the above pointer value will be returned to the calling function, and the pointer will be readjusted to point to the next available memory space. Allocating a block of managed memory is only slightly more complicated than incrementing the value of a pointer. This is also one of the performance optimizations of the managed heap. In an application that does not require much garbage collection, the managed heap will perform better than the traditional heap.
Due to this linear memory allocation method, objects allocated simultaneously in C# applications are usually allocated adjacent to each other on the managed heap. This arrangement is completely different from traditional heap memory allocation, which is based on memory block size. For example, two objects allocated at the same time may be located far apart on the heap, reducing cache performance. Therefore, although memory allocation is fast, in some more important programs, the available memory in generation 0 is likely to be completely consumed. Remember, generation 0 is small enough to fit in the L2 buffer, and unused memory is not automatically freed. When there is no valid memory that can be allocated in generation 0, a round of garbage collection will be triggered in generation 0. In this round of garbage collection, all objects that are no longer referenced will be deleted and objects currently in use will be deleted. Moved to generation 1. Generation 0 garbage collection is the most common type of collection, and it is very fast. When the garbage memory collection of the 0th generation cannot effectively request sufficient memory, the garbage memory collection of the 1st generation is started. Generation 2 garbage collection should be used as a last resort if and only if generation 1 and generation 0 garbage collection cannot provide enough memory. If there is still no available memory after each generation has been garbage collected, an OutOfMemeryException will be thrown.
(4) Java garbage collection mechanism
## How is the memory placed when executing a Java program? Six places are mentioned in the book "Java Programming Thoughts":
(1) Register (Register)
(2) Stack ( Stack)
(3) Heap: used to place all Java objects
(4) Static storage ): Used to store data that exists "during program execution". Modified with statci.
(5) Constant storage
(6) Non-RAM storage space: I understand it as a disk storage area, That is, non-memory area.
Sun HotSpot 1.4.1 uses a generational collector, which divides the heap into three main domains: new domain, old domain and permanent domain. All new objects generated by the Jvm are placed in the new domain. Once an object has gone through a certain number of garbage collection cycles, it acquires its lifetime and enters the old domain. In the permanent domain, the jvm stores class and method objects. For configuration purposes, the persistent domain is a separate domain and is not considered part of the heap. From this point of view, the JVM using HotSpot engine technology should adopt a garbage collection mechanism similar to the .NET framework - generational garbage collection method.
The following describes how to control the size of these domains. You can use -Xms and -Xmx to control the original size or maximum size of the entire heap.
The following command sets the initial size to 128M:
java –Xms128m
-Xmx256m To control the size of the new domain, you can use -XX:NewRatio to set the proportion of the new domain in the heap.
The following command sets the entire heap to 128m and the new domain ratio to 3, that is, the ratio of the new domain to the old domain is 1:3, and the new domain is 1/4 of the heap or 32M:
java –Xms128m –Xmx128m
–XX:NewRatio =3 You can use -XX:NewSize and -XX:MaxNewsize to set the initial value and maximum value of the new domain.
The following command sets the initial value and maximum value of the new domain to 64m:
java –Xms256m –Xmx256m –Xmn64m
The default size of the permanent domain is 4m. When running a program, the jvm adjusts the size of the persistent domain to suit needs. Every time you adjust, the jvm will perform a complete garbage collection on the heap.
Use the -XX:MaxPerSize flag to increase the permanent domain size. When a WebLogic Server application loads more classes, it is often necessary to increase the maximum size of the permanent domain. When the jvm loads a class, the objects in the permanent domain increase dramatically, causing the jvm to continuously adjust the permanent domain size. To avoid adjustments, use the -XX:PerSize flag to set an initial value.
Next, the initial value of the permanent domain is set to 32m, and the maximum value is set to 64m.
java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m
By default, HotSpot is in the new A replication collector is used in the domain. The domain is generally divided into three parts. The first part is Eden, which is used to generate new objects. The other two parts are called rescue spaces. When Eden is full, the collector stops the application and copies all reachable objects to the current from rescue space. Once the current from rescue space is full, the collector copies the reachable objects to the current from rescue space. The to rescue space. From and to rescue spaces swap roles. Objects that remain alive will be replicated in the salvage space until they expire and are transferred to the old domain. Use -XX:SurvivorRatio to control the size of the new domain subspace.
Like NewRation, SurvivorRation specifies the ratio of a certain rescue domain to Eden space. For example, the following command sets the new domain to 64m, Eden occupies 32m, and each rescue domain occupies 16m:
java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2
As mentioned before, by default HotSpot uses the replication collector for new domains and the mark-sweep-compact collector for old domains. Using a copying collector in a new domain makes a lot of sense because most objects generated by an application are short-lived. Ideally, all transition objects will be collected when moved out of Eden space. If this is possible, and the objects moved out of the Eden space are long-lived, then in theory they can be moved into the old space immediately to avoid repeated copying in the rescue space. However, applications cannot fit into this ideal state because they have a small proportion of medium to long-lived objects. It is better to keep these medium to long-lived objects and place them in the new domain, because it is cheaper to copy small parts of the objects than to compress the old domain. In order to control the copying of objects in the new domain, you can use -XX:TargetSurvivorRatio to control the ratio of the rescue space (this value is to set the usage ratio of the rescue space. For example, if the rescue space is 1M, the value 50 means 500K is available). The value is a percentage, and the default value is 50. When larger stacks use a lower sruvivorratio, this value should be increased to 80 to 90 to better utilize the bailout space. Use -XX:maxtenuring threshold to control the upper limit.
To ensure that all replication occurs and that you want objects to be extended from eden to the old domain, set MaxTenuring Threshold to 0. After the setting is completed, the rescue space is actually no longer used, so the SurvivorRatio should be set to the maximum value to maximize the Eden space. The settings are as follows:
java ... -XX:MaxTenuringThreshold= 0 –XX:SurvivorRatio=50000…
Postscript: As mentioned in "The 10 Years of the Java Virtual Machine", "The last five years , that is, (JVM) continues to optimize. There are several ways to continue optimization. One is to study new sampling algorithms, because sampling is related to different optimization strategies and will have a relatively large impact on overall performance. Study deep optimization methods. The third is to study garbage collection algorithms. Garbage collection will cause a short pause in the program, which will bring negative user experience. Therefore, a variety of algorithms have emerged to improve the efficiency of garbage collection and reduce delays. , such as progressive collection, train algorithm, etc. "Improving the execution speed and efficiency of the language has always been the goal pursued by designers and developers, so garbage collection algorithms will also develop with the passage of time. I don’t think any interviewer would dare to ask you about the garbage collection mechanism of C# or Java (at least I haven’t encountered it yet). Once the discussion is in-depth, many issues are enough to write a long book. But it is really a beautiful thing to inquire deeply and trace the origin. Confucius climbed the Dongshan Mountain and became a small Lu, and climbed the Taishan Mountain and became a small world.
The above is the detailed introduction of the garbage collection mechanism of Java and C#. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!