Some time ago I read some papers, books, and source code about GC. The source code refers to Boehm's conservative GC, which is mainly related to this GC.AlgorithmAnd also includes some survey and performance analysis papers. Some other items about GC are mainly from the perspective of the other two books. One is the garbage collection translated by Xie Zhiyi's boss. Currently, the only book on GC Algorithms, also, I carefully read the information in C # via CLR.. Net GC. I originally wanted to make a summary of the GC algorithm, but I gave an introduction to GC in C ++ in the lab a few days ago, it is found that other basic GC problems require better analysis than algorithms.
About GC in C ++, G9 boss has made a beautiful overview. What I want to do is sort out my logic. You are welcome to copy bricks, ^_^.
The first question is, why do we need GC?
Or, in C ++, what does GC bring to us. In many cases, GC is involved in a discussion about performance. It is true that mm (or JJ, or
Aunt, or aunt, or mother-in-law...) pp level has a great impact on appetite, but for a normal body and mind (if crazy or don't use then throw
Btexception) for ELE. Me people, the priority must be taste and cost effectiveness. For GC in C ++, the following factors are equivalent to taste and price:
1. It is simpler and safer than human resource management. Meyers has a lot to describe about its security.
, Usually a big human c ++ProgramIt is impossible to avoid resource leaks. The new/delete mode of C ++ is very complicated for many non-C ++ programmers. If you
This is a secondary development platform. Many developers in the future are non-C ++ programmers, forcing people to understand such a general memory management mode, which is inhuman and insecure. If it is a full GC Process
Safety (on the premise that the GC is safe...) and easy to use are all at hand.
2.
Better comprehensibility. In human c ++, we all need to put a lot of effort into checking and writing the memory management part. New and delete are mixed inCodeA little careless. Special
Is an interface like a * geta () (delete or
Not), without the help of documents, it is almost incomprehensible (and documents often cannot meet the requirements ). In GC programs, the code is clearer and the interface does not have puzzle.
Therefore, before you decide whether to use GC, consider whether you have the above two requirements. If you are half-dead or eager for PPMM exceeds everything, forget it. GC is not yours.
Dishes in the bowl. If OK, this is exactly what you need. So the next thing to consider is whether the GC dish is delicious and versatile? Whether there are other similar dishes makes me anxious.
In other words, how is GC efficiency, compatibility, and so on? Is there any other solution that meets the above two requirements and is outstanding in other aspects?
The second question is, why are we afraid of GC?
The reasons for rejecting GC are often not the above two reasons. The reason why I want to elaborate on the above is that many people often forget these huge advantages when considering the following problems (maybe... include me), and fell into a well and looked at the sky. Well like this should include the following:
1. Low GC Efficiency
2. High GC memory usage
3. The stop-the-world working mode is terrible.
4. Handing over Memory Management to GC is not safe
5. Unable to be compatible with Human Resource Management Code
6. Memory collection is not timely enough
7. other things I don't know... (ranking in no particular order ^_^)
These are the reasons why people are afraid or refuse to use GC. If you consider the simplest GC model, these problems may exist. However, GC has been studied for N years, and GC in C ++ has been studied for more than 20 years. Three days later, I was surprised to see that, not to mention that for so many years, I should have changed my mind.
The first problem to be solved is the allocation efficiency. GC Allocation performance is generally considered for Allocation performance. Generally, tracing-based garbage collection algorithms are slow in allocation and fast recovery. Scale-down (move now)
(1) memory allocation. For example, GC allocation in. Net is a constant-level loss, but non-moving memory is usually not slow due to redundancy. The key lies in the long tracking time. In Boehm
In the GC, many algorithms aim to improve the tag efficiency. This improvement is not only based on the complexity of the algorithm (the aging can be considered as the method to optimize the tag complexity ), more from the page missing rate and Cache
The Miss rate is increased. In an evaluation of the Boehm GC by Zorn in, we can see that (the current GC performance should be better in terms of allocation efficiency, page drop rate, and cache miss rate, however, we cannot find the relevant paper × _ ×), even if the conservative GC allocation efficiency is very good. The GC application of cloud wind's predecessors in NetEase games can be seen as a specific GC design path (which cannot be used as a general library, but is easy to implement). I believe this will provide better efficiency. Especially with the popularization of multiple cores, the efficiency of concurrent-based GC algorithms is even more outstanding. Therefore, allocation efficiency (of course, in most application scenarios) will not be the reason for rejection.
However, I think the memory usage will become a problem (2 and 6 are actually similar. The high usage is mainly due to pre-allocation and deferred return ). From the Zorn evaluation, we can see that beohm
GC is about twice the memory usage of the human meat distributor. In fact, if you think about the GC principle carefully, you can understand that there is no memory redundancy, and GC is almost impossible.
Is it GC ?), Of course, the operating system sometimes performs redundancy (query tables), but it should be much more conservative than GC. Even so, I think the memory usage is as high as Boehm.
GC distributor-related, because the Mark-sweep (Mark cleaning, non-mobile GC algorithm) algorithm is used, memory holes may occur (a large block of memory is occupied by a small amount of actually used memory, other departments
Points cannot be used by objects of varying sizes), and because the boundary is aligned to 2 ^ N, there may be about 50% memory loss. Therefore, I want to improve the memory distributor (we need to do
Memory distributor? Of course, because we allocate on the hosting stack, the operating system's existing allocator is good, and it doesn't help us), there should be a certain reduction in memory usage. In addition, if Mark is used
-Compact
GC) There will be no alignment loss. redundant memory blocks can better meet the virtual memory mode (not to put them together, but to put them together), which should also reduce the memory usage.
Stop-the-world is a situation that most mainstream GC will occur (Yes, Count-based GC won't have this problem, but...), in some cases (high interaction ?) May
It becomes a big problem. I personally think this is also an inevitable problem, just as you cannot run one hundred meters at a speed (you can run m to 2 '? OK... I didn't say so ). However
A lot of work to reduce this pause. In Boehm GC, there are methods such as delayed cleaning, parallelism, and age generation. However,. Net GC sets the goal of one GC startup pause to 1 ms, that is, the loss of a page missing, and does not know whether the measured condition can be achieved. If you can, I think most of the cases can be tolerated.
Is the memory safely transferred to GC? Well, this is a problem in C ++. Because c ++ is unable to identify the type during runtime, it is a problem of vomiting blood in a bowl of big cows. Boehm is
This can be said to be useless, but in any case, it is theoretically impossible to put an end to the possibility of GC errors (unless programmers help ^_^ ). But I think, in this year, the most insecure is people themselves * _ ^.
Compatibility issues. Well... a big problem. For example
Real ...). In the project, some memory is allocated by humans, and the other part is GC allocation. When a non-GC object in the stack points to a non-GC object in the heap, this heap object will not be scanned (because
GC is not recognizable as the address indicated by the stack object. If the heap object points to the GC object in another managed stack (and no one references it again), this object will not be marked, that is to say, GC will
This results in terrible results (when the... program game
Over ). To avoid this situation, it is best to ensure that all objects are in a traceable or recoverable state. In the case that the source code can be changed, the theory only needs to reload all the related distributors.
(Including global, overloaded, STL ...). But there is a problem I don't know. If it is a multi-root scenario (for example, an MFC program, all classes are derived from cobject), it can be modified.
Source code, this problem is not easy to solve (can the cobject distributor be closed? Ask ing...), not to mention other situations where the source code is not controlled. (let's take a look at what G9's boss listed... but let's solve it.
Sample, which must be in two States ).
Finally, let's take another dish and compare it with the counting pointer. As the saying goes, we are afraid of goods comparison if we don't know the goods. In fact, it is unfair to put the counting pointer here because it cannot provide the GC capability.
The most basic benefits provided (taste a little sour ...), because it is not easy to use enough (the pointer is not a person, and you will not wear clothes consciously ...), it will also mess up the code. In terms of efficiency, the counting pointer is direct
Game
But from the memory utilization and delay, the counting pointer will be better. In terms of security, the counting pointer is still dependent on people; in terms of compatibility, half a catty to eight two. So, you don't have to fight for anything.
Your yangguan road is good for me to use my zhuqiao (but I don't think it is a good idea to use them at the same time ...).
Third question: Do C ++ need GC?
So far, we can summarize it. The advantage of applying GC is that it can provide more secure and understandable code, and it does not have to pay too much extra cost, making memory management easier. Its Disadvantages include: Some may have low allocation performance, more memory usage, and the pause is still inevitable. There are still some security risks, not as close as the old c ++.
Then, do we need to use GC in C ++. We will answer this question in two steps. First, we need c ++ to do some projects, which are not suitable for other languages. In addition, we can endure these shortcomings in these projects, the above advantages are also required. Is there such a project? Let's take a look at the application status of G9's blogs and Boehm GC.
Most of the time, we have limited the GC application to memory management. In fact, there are many GC usage methods. You can use GC to manage memory in a certain part of the project. You can use GC as a leak detector, or even use GC as a debugger. In this way, GC is more required in C ++.
The fourth question is, what are the advantages of GC in C ++ 0x?
After reading the above content, this problem is basically nonsense. What do we fear when using GC in C ++? The shortcomings mentioned above. What are the advantages of GC in C ++ 0x? It can solve most of the above shortcomings (efficiency, security, and compatibility), because these shortcomings do not belong to GC, but only to GC in C ++.
The fifth question is, what kind of GC should we perform in C ++ 0x?
After reading the proposes of GC, we can see that the old guys have spent a lot of effort in C ++ 0x for GC. If you are interested, you can check the proposes. I personally think that GC into C ++ 0x can be considered in three aspects. One is the library, the other is the compiler, and the other is the syntax support.
I think the GC library is the most basic. Boehm GC is a standard, and the replication-based library can also be examined. However, without any compiler-level adjustments, All GC libraries will have the above problems. The support at the compilation stage is most likely as cloud wind's predecessors imagined,
A compilation switch is provided. When GC is enabled, the object can be identified during runtime, which ensures the security of GC (pure GC, and greatly improve the efficiency (you can also manually set the atomic class,
However, this increases the writing burden ). If there is no compatibility with the old Code and you only want to build a pure gc c ++ Program (or library), this is very feasible (of course, it will pay more memory costs ).
However, the most unsatisfactory situation is the human c ++ interaction. The old guys come up with a bunch of keywords and usage methods to address this situation only (if this situation does not exist, almost no new
Keyword, and you only need to extend the new and finalization-related functions), of course, this will bring more complicated situations in use. However, as long as you don't want to, you don't need GC, because
It is optional for everything.
Therefore, I think the current GC method into C ++ 0x is still very good. Most of the situations meet the requirements. If there are a small number of interactions with the old guys, you can handle them. If there are more complicated situations, no GC is used, the world is the same.
PS: the general situation of GC in C ++ 0x is as follows:
Garbage collection:
For C ++ 0x, we're not going to add explicit support for garbage
Collection, and only intend to find ways to remove blocking issues like
Pointer hiding that make it difficult to add garbage collection in
C ++ implementation. In particle, the scope of this feature is
Expected to be constrained as follows:
- C ++ 0x will include
Making some uses of disguised pointers # ff0000, and providing a small
Set of functions to exempt specific objects from this restriction and
To designate pointer-free regions of memory (where these functions
Wocould have trivial implementations in a non-collected conforming
Implementation ).
- C ++ 0x will not include explicit syntax or
Functions for garbage collection or related features such
Finalization. These cocould well be considered again after C ++ 0x ships.
What do you think?
Document list:
[Boehm, 1992] A Proposal for Garbage Collector safe C compilation.
[A]
Explains why the garbage collection is not secure when the C compiler enables optimization. This kind of insecurity mainly comes from pointer determination. The Compiler sometimes takes some extreme measures to process pointers to achieve
Optimal efficiency, resulting in less obvious features of the pointer. This article also proposes to avoid such insecure content. The blacklist technology is used in actual implementation.
[Boehm, 2002] bounding space usage of conservative garbage collectors.
[A] To avoid pointer errors, the conservative Garbage Collector needs a lot of space to determine the pointer. In order to limit the utilization rate to a certain range, in this paper, the concept of weak robustness is proposed, that is, the usage of pointers can be limited to a certain extent, and the author makes a mathematical proof.
[Boehm, 2000] fast multiprocessor memory allocation and garbage collection.
[A] The implementation and performance of Boehm GC on multi-thread multi-processor are analyzed and compared in detail.
[Boehm, 1988] garbage collection in an uncooperative environment.
[A] The concept of Boehm GC is described in detail.
[Boehm, 1993] space efficient conservative garbage collection.
[A] This article analyzes how to perform efficient pointer scanning and determination, discusses possible pointer judgment errors, and the strategies that have been taken.
[Boehm, 1996] Simple Garbage Collector safety.
[A] discussing the issue of garbage collection insecurity at the compiler level.
[Boehm, 2000] cing Garbage Collector cache misses.
[A] describes how to increase the cache hit rate in Boehm GC.
[Henderson, 2002] accurate garbage collection in an uncooperative environment.
[A]
In the conservative GC represented by Boehm GC, it is necessary to traverse the stack and register to determine the root pointer. This determination does not have any type guarantee, and there is a risk of memory overflow caused by misjudgment. To avoid this
Dangerous. from another perspective, this article adds GC-related information to the C code in the stage of generating C code by the compiler, so that the pointer in the stack can be identified more accurately.
[Ellis, 1993] safe, efficient garbage collection for C ++.
[A] describes a GC in C ++ method and provides an overview of the previous work.
[Wilson, 1992] uniprocessor garbage collection techniques.
[A] survey describes several basic garbage collection algorithms and progressive and aging technologies.
[Hertz, 2005] garbage collection without Paging
[A] a garbage collection algorithm is proposed to reduce paging.
[Berger, 2000] hoard: A Scalable Memory Allocator for Multithreaded Applications.
[A] describes a multi-processor and multi-thread memory distributor.
[Hertz, 2005] quantifying the performance of garbage collection vs. Explicit Memory Management.
[A] comparison of the performance of garbage collection and human flesh collection.