Here, the destructor is not accurate, it should be called the Finalize function, the Finalize function form and C + + destructor is very similar, are (~classname) Form, but functionally completely different. After the destructor is compiled into the Il language, it becomes a finalize function, which is a finalize virtual function of the overridden object, with a destructor on the title, mostly I think many people do not know the Finalize function.
Writing a type explanation may be more understandable:
Public class Test { ~test () {} // This is the Finalize function . Private byte New byte [10000]; }
Recently read some code, there are many with the Finalize function. In particular, in the EF Data Warehouse, the situation is as follows:
Public class dbrepostoty{ Private context context; Public Dbrepostoty (Context context) { this. Context = context; } ~Dbrepostoty () { context. Dispose (); }} Public class context:dbcontext{}
It looks big, but is it good to write like this? Okay, well, let's go back to the final comment and take a look at the following simple example:
Public classWithfinalize {~withfinalize () {}Private byte[] B =New byte[10000]; } Public classWithoutfinalize {Private byte[] B =New byte[10000]; } classProgram { Public Static voidMain (string[] args) {Console.WriteLine ("Test 1No finalize function:"); Test<WithoutFinalize>(); Console.WriteLine (Environment.NewLine+"Test 2There is a finalize function:"); Test<WithFinalize>(); Console.readkey (); } Public Static voidTest<t> ()whereT:New() {GC. Collect (); Thread.Sleep (Ten); Console.WriteLine ("Initial Memory:"+ GC. Gettotalmemory (false)); varList =NewList<t>(); for(inti =0; I <Ten; i++) List. ADD (NewT ()); Console.WriteLine ("after allocation:"+ GC. Gettotalmemory (false)); Gc. Collect (); Thread.Sleep (Ten); Console.WriteLine ("One recycle:"+ GC. Gettotalmemory (false)); Gc. Collect (); Thread.Sleep (Ten); Console.WriteLine ("two times recovery:"+ GC. Gettotalmemory (false)); } }
This code has three classes one is the main program that we need to run, and the other two whitfinalize and whitoutfinalize are the types we want to test, the two classes one with the Finalize function, one without, the rest is exactly the same. The main program is to test the performance of these two types at the time of garbage collection, we first tested the type without the Finalize function, and added the type to the test. A total of four values, respectively, is the initial memory, new 10 test type after the memory (test type about 10k of memory space, 10 is about 100k), garbage collection once after the memory, garbage collection two times after the memory, we look at the specific operating conditions:
Test 1 No Finalize function: Initial memory: 96224 after allocation: 1,964,641 recycles: 970,362 recycles: 97036 Test 2 has finalize function: Initial memory: 97056 after allocation: 1,972,961 recycles: 1,973,962 recycles: 97156
From the running situation, the initial memory of two Tests is about 97k, the new 10 test objects grew by about 100k, as expected, but after the first garbage collection Test 1 (no finalize function) to reclaim about 100k of memory, Test 2 (with the Finalize function) basically does not reclaim memory, but waits for a second garbage collection to reclaim 100k of memory. Can not help but think, this is why?
This has to do with some of the principles of garbage collection, things are more, we say simple. Garbage collection is the time to traverse all referenced objects from the root, and then iterate to make the markup, which is useful, not to be traversed is garbage, but in these garbage there are some objects define the Finalize function, so they have the finalize object from the garbage heap to pull back, The rest of the garbage is recycled, and these dead and resurrected objects survived with those that were not, and are upgraded to next-generation objects, and the CLR uses a higher-priority thread to invoke the Finalize method of these dead and resurrected objects after the garbage collection ends. They are not recycled until the next garbage collection. That's why we've seen Test 2 the second time garbage collection is recycled, and we're talking about something sketchy here, and the internal implementation is complicated.
We saw that I used a lot of thread.sleep (10) in the code; What is the reason for this? That's what I was saying. " after garbage collection is over, the CLR uses a higher-priority thread to invoke the Finalize method of these dead and resurrected objects , and the call to the Finalize method and our foreground code are concurrent, And our front-desk code is relatively simple, if not paused, it is likely that many of the object's Finalize method has not finished, we call the next garbage collection (Gc.collect ()). affect the accuracy of the results.
And we mentioned the concept of generation, here is also a simple generation, garbage collection when the object of a total of three generations: 0,1,2. Each generation has its own memory budget, and garbage collection is called when there is not enough space. In order to improve performance is on behalf of the recovery, the No. 0 generation of super-budget after the recovery of the No. 0 generation of objects, and the survival of the object is promoted to 1th generation, and so on, and often after several 0 generations of garbage collection to reclaim the 1th generation.
Gc.collect () in our code, without parameters, means to reclaim all generations of objects, we can replace Gc.collect () with Gc.collect (0), which means to reclaim the No. 0 generation object and then run the program:
Public Static voidTest<t> ()whereT:New() {GC. Collect (); Thread.Sleep (Ten); Console.WriteLine ("Initial Memory:"+ GC. Gettotalmemory (false)); varList =NewList<t>(); for(inti =0; I <Ten; i++) List. ADD (NewT ()); Console.WriteLine ("after allocation:"+ GC. Gettotalmemory (false)); Gc. Collect (0); Thread.Sleep (Ten); Console.WriteLine ("One recycle:"+ GC. Gettotalmemory (false)); Gc. Collect (0); Thread.Sleep (Ten); Console.WriteLine ("two times recovery:"+ GC. Gettotalmemory (false)); }
Test 1 No Finalize function: Initial memory: 96224 after allocation: 1,964,641 recycles: 970,562 recycles: 97036 Test 2 has finalize function: Initial memory: 97056 after allocation: 1,972,961 recycles: 1,973,962 recycles: 197396
We see that memory in Test 2 is still not recycled after the second garbage collection (for the No. 0 generation), which is closer to the actual situation.
From the small example above we learned that the Finalize method has a bad effect on both performance and memory, so why do we have this method? Here we talk about two scenarios for using finalize:
The first is that the object contains a native resource, such as a handle, so that the handle can be released in the Finalize method, eliminating the waste of native resources caused by forgetting to release the handle.
The second case is to do something that must be done before the object is recycled, such as the FileStream class, which needs to write the buffer to the file before it is recycled.
We look back at the Data Warehouse class mentioned earlier, this class first does not occupy any native resources, the second before being recycled there is no need to do things, write a Finalize method and invoke the context. Dispose (); Can only increase the performance overhead, affecting the garbage collection effect. We can use the anti-compilation software to see DbContext this base class, he did not finalize the method, and why the lily?
I hope I feel helpful to my friends to give me a praise ('? '). )
A talk about the impact of. NET destructors on garbage collection