. Net Detailed garbage collection mechanism

November 6, 2011
http://www.cnblogs.com/tianzhiliang/archive/2011/0 3/06/1972604.html1. Automatic memory management and GC
in the original program heap memory allocation is this: find the first to have enough memory address space (not occupied), then the memory allocation. When the program no longer needs this information in memory when programmers need to manually release this memory. Heap memory is common, meaning that all processes are likely to cover the contents of the memory of another process, which is why a lot of poorly designed program or operating system itself will fall down. We sometimes encounter unexplained dead program (random phenomena), but also because of improper memory management (possibly because of their program or external program memory problems caused). Another common example is that we often see the game Trainer, their memory by directly modifying the game to “Invincible” effect. Understand that we can imagine that if the memory address of these were confused with how dangerous it would be, we can also imagine why C programmers (some of) the mention of the pointer on the causes of headache. In addition, if program memory is not the case then the programmer to manually release the memory will not be re-allocated until the computer re-starting up, what we call a memory leak. These are referred to in unmanaged code, CLR AppDomain to achieve through the isolation between the code to avoid these memory management problems, that under normal circumstances one AppDomain can not read / write memory to another AppDomain. Managed memory is released on the GC (Garbage Collector) to be responsible. We want to further talk about is the GC, but before that first talk about the allocation of memory in managed code, the managed heap memory allocation is sequential, meaning that the allocation of a next one. This memory allocation is higher than, the original program, but the speed will be higher than the GC looking back. Why? After reading the GC work you will know the answer.
2. GC work
First, we need to know what the objects in managed code, when we recall to mind (unless GC.Collect to force GC collection, this is not recommended, will explain why later). GC will be in its “happy” when the implementation of a recovery (for many reasons, such as the memory is not enough time. This is done to improve memory allocation, collection efficiency). So if we use the Destructor it? Did not work, because. NET in the Destructor of the concept does not exist, it becomes a Finalizer, which will be shown later. Remember that an object is present only in the absence of any reference to circumstances that can be recycled. To illustrate this point consider the following piece of code:
objectobjA = newobject ();
objectobjB = objA;
objA = null; < br />
/ / to force recovery.
GC.Collect ();
objB.ToString ();
here objA referenced object has not been recovered, because the object also There is another reference, ObjB. In the absence of any reference to the object to be recovered after the conditional.
When the GC recovery, it will do the following steps:
1, to determine the object does not have any references.
2, check whether the object is recorded on the table in the Finalizer. If there are records in the Finalizer table, then moved to another record on a table, where we call it Finalizer2. If you do not Finalizer2 record on the table, then release the memory. In Finalizer2 Finalizer objects on the table will be a low priority in another thread on the execution removed from the table. When the object is created, the GC will check whether the object has Finalizer, if there will be added to the table records in the Finalizer. We are talking about here is actually the record pointer. If you look closely these steps, we will find a Finalizer object for the first time will not be recovered, that is, there is more than one Finalizer object to the Collect operation will be recycled, so we should slow step, so the authors recommended unless it is absolutely necessary not to create a Finalizer.
GC in order to improve the efficiency of the use of recycled Generation of the concepts, principles, this is the first object is created before the recovery of Generation 0, after the recovery time when the number will be back this Generation Norwegian one, that is, the second recycling into the original Generation 0 Generation 1, but recovered in the first and second objects created before recovery will belong to Generation 0. GC will first try to belong to Generation 0 objects in the collection, because these are the latest, the most likely to be recycled, such as some function of local variables in the exit function is not quoted (which can be recycled). If the Generation 0 recovered enough memory, then the GC will not be followed by recovery, if recovery is not enough, then the GC will try to recover in the Generation 1, if it is not recovered in the Generation 2, this and so on. Generation also has a maximum limit, according to the Framework version, you can use GC.MaxGeneration available. In the recovery of memory after GC will reschedule the entire memory, so there is no space between the data, this is because the CLR in order to allocate memory, it can not free the memory between the memory. Now we know that each time a certain recovery time will be wasted CPU time, this is what I say in general do not manually GC.Collect reasons.
When we Destructor syntax, the compiler will automatically write it as a protected virtual void Finalize (), this method is what I call the Finalizer. As the name says, it used to end certain things, not to destroy (Destruct) things. In Visual Basic, it is the Finalize method of the form, so Visual Basic programmers do not have to worry about. C # programmers use statistics Destructor syntax to write Finalizer, but do not confused,. NET has no Destructor up. C , we can accurately know when it will perform Destructor, but in. NET, we can not know when it will implement Finalizer, because it is the first object in the recovery operation after the implementation. We can not know that Finalizer execution order, that is the same case, A Finalize may be executed first, B after the execution, execution may be A and B after the first run. In other words, the code in the Finalizer, we can not have any time logic. Here we calculate the number of instances of a class as an example, that the different Destructor and Finalizer and Finalizer in that time in a logical error:
publicclassCountObject {
publicstaticintCount = 0;
publicCountObject () {
Count ;
}
~ CountObject () {
Count -;
}}
staticvoidMain () {
CountObject obj;
for (inti = 0; i <5; i ) {
obj = null; / / This step is redundant, so just to write some more clearly!
obj = newCountObject ();
}
/ / Count will be 1, because the Finalizer will not immediately be triggered until there is a recovery operation will be triggered.
Console.WriteLine (CountObject.Count);
Console.ReadLine ();
}
Note that the above If the switch to C code to write, then memory leaks will occur, because we do not use the delete operator to manually clean up the memory, but not in managed code is a memory leak, because the GC does not automatically detect and recover the object references. Here the author recommended that you implement the IDisposable interface only when used in conjunction with Finalizer, in other cases do not use (there may be special circumstances).
3. the object of the resurrection
what? Recovery of the object can also be “resurrected” it? Yes, although the definition is not accurate to say. Let look at some code:
publicclassResurrection {
publicintData;
publicResurrection (intdata) {
this . Data = data;
}
~ Resurrection () {
Main.Instance = this;
} }
publicclassMain {
publicstaticResurrection Instance;
publicstaticvoidMain () {
Instance = newResurrection (1); < br />
Instance = null;
GC.Collect ();
GC.WaitForPendingFinalizers ();
/ / to see to do, where “resurrection”.
Console.WriteLine (Instance.Data);
Instance = null;
GC.Collect ();

Console.ReadLine ();
}}
You may ask: “If this object can be resurrected, then this object in the program will be recycled after the end of it?” . Will be, “Why?.” Let us take the work in accordance with GC once you understand how the matter.
1, perform Collect. Check the references. No problem, the object has no references.
2, create a new instance of the table has been made in the Finalizer record, so we checked into the object has Finalizer.
3, as found in the Finalizer, so the record moves Finalizer2 table.
4, in Finalizer2 table record, so I do not release memory.
5, Collect is finished. Then we use the GC.WaitForPendingFinalizers, so we will wait on the table Finalizers all Finalizer2 implementation.
6, Finalizer execution of our Instance on another reference to our object. (Resurrected)
7, once again to remove all references.
8, perform Collect. Check the references. No problem.
9, has since the last record deleted from the Finalizer table, so this is not found objects Finalizer.
10, in Finalizer2 table does not exist, so the object memory is released.
release unmanaged resources until now, we say that the managed memory management, so when we use such as databases, files and other unmanaged resources it? At this time we have to use the. NET Framework Standard: IDisposable interface. As standard, all you need to manually release the unmanaged resource class had to implement this interface. The interface has one method, Dispose (), but there are relatively Guidelines indicate how to implement this interface, and here I talk to you. This class implements the IDisposable interface, the need for such a structure:
publicclassBase: IDisposable {
publicvoidDispose () {
this.Dispose (true) ;
GC.SupressFinalize (this);
}
protectedvirtualvoidDispose (booldisposing) {
if (disposing) {
/ / managed class
}
/ / release unmanaged resources
}
< br /> ~ Base () {
this.Dispose (false);
}}
publicclassDerive: Base {
< br /> protectedoverridevoidDispose (booldisposing) {
if (disposing) {
/ / managed class
}
/ / release unmanaged resources
base.Dispose (disposing);
}}
Why this design? Let me explain what followed. Now we talk about the Dispose method to achieve this several criteria: it does not throw any errors, repeat the call can not throw an error. That is, if I have an object called Dispose, Dispose is called when my second time the program should not be wrong, simply call Dispose in the second program will not do anything. These can determine if a flag or multiple realization. Dispose of an object to achieve the release of all the resources of this object. Take for example a derived class, derived class uses unmanaged resources, so it implements the IDisposable interface, if the class inherits the base class also uses unmanaged resources, the base class have to be released, how the resources of the base class in the derived class release it? Of course, is a virtual / Overridable methods, and so we are able to guarantee that each call to Dispose. This is why we have designed a virtual / Overridable Dispose method. Note that we first have to release the resource class inherit the base class and then release the resources. Because unmanaged resources must protect the right to be free so we have to define a Finalizer to avoid programmers forget to call Dispose of the situation. The above design on the use of this form. If we manually call the Dispose method is not necessary to retain Finalizer, so we used in the Dispose GC.SupressFinalize remove the object from the Finalizer table, so that when the recycling rate will be faster. So that disposing and “managed class” is how it happened? Is this: in the “managed class” write all you want to call Dispose can be released so they are in the state of managed code. Remember we said that we do not know when to release the managed code is it? Here we just get rid of members of the object reference it can be recycled in the state, not directly to free memory. In the “managed class” in here, we write all the members of the object implements IDisposable, because they also have a Dispose, so it needs to call the object Dispose their Dispose, so as to ensure that the second criterion. disposing to distinguish call the Dispose method, if we call it manually to the second criterion, “managed class” part of the course was implemented, but if it is Finalizer calls Dispose, this time the object has no references, that is a member of an object not exist naturally (no reference), there is no need to implement “managed class” section, because they can be recycled in the state. Well, this is all the IDisposable interface. Now let us recall the past, we may think that memory will soon have a Dispose released, this is wrong. Only unmanaged memory will be immediately released, the release managed memory managed by the GC, we do not control.
4. weak references use
A = B, we call such a reference is called a strong reference, GC is a strong reference to the decision by checking whether an object can be recycled . There is also a reference called weak references (WeakReference), this reference does not affect the GC recovery, this is where it useful. You may ask what is the use in the end. Now let assume we have a fat object, which means it takes up a lot of memory. We used this object, it intends to remove the reference to memory so GC can be recycled, but much effort we need this object, and no way to re-create the instance, how to create such a Mana? Is there any way to solve this problem? There, the objects behind in memory not to fast it! But we do not want too fat to total occupied memory object, and we do not want to always create a new instance of this fat because this is very time consuming. How to do that …? Smart friends must have guessed I would say that solution is a weak reference. Yes, that it. We can create a weak reference object of this fat, so that GC can be recycled when the memory is not enough, does not affect the memory usage, and in the GC has not been recovered before we can re-use of the object. Here an example:
publicclassFat {
publicintData;
publicFat (intdata) {
this.Data = data;
}}
publicclassMain {
publicstaticvoidMain () {
Fat oFat = newFat (1);
WeakReference oFatRef = newWeakReference (oFat);
/ / From here, Fat object can be recovered.
oFat = null;
if (oFatRef.IsAlive) {
Console.WriteLine (((Fat) oFatRef.Target). Data) ; / / 1
}
/ / mandatory recycling.
GC.Collect ();
Console.WriteLine (oFatRef.IsAlive); / / False
Console.ReadLine ();
}}
Fat is not really where our fat, but can reflect the intention of examples: How to use weak references. Finalizer that if Fat has it, what will happen? Fat Finalizer if we could have used another WeakReference constructor, which has a parameter called TrackResurrection, if it is True, as long as the Fat of the memory is released we can not use it, that Fat After we perform the Finalizer can be restored Fat (equivalent to the first recovery operation can resume Fat); if TrackResurrection is False, then the recovery operation after the first object of the Fat can not be restored.
5. Summary
I am here to write a positive article main points:
an object only when there is no reference in the case of will be recycled.
an object memory is not released immediately, GC will be recovered at any time. Generally do not enforce recycling.
If there is no special need not write Finalizer.
Finalizer do not have time to write some logic in the code.
in any unmanaged resources Dispose of or containing members of the class implement the IDisposable interface.
Dispose in accordance with the design given in the Dispose write their own code.
When fat can be considered weak object references to use.

Posted: January 3rd, 2012
at 2:23pm by admin

Tagged with


Categories: Uncategorized

Comments: No comments