Release compilation mode, whether the event will cause a memory leak problem preliminary study

Source: Internet
Author: User

Remember: Infrequently occurring event memory leaks

Some friends may also often use events, but few release the event hook program or have heard of problems like memory leaks. Fortunately, in some cases, it does not go wrong, and many years ago the project ran well, and we can do an experiment to verify it again. In order to verify this problem, I once suspected that the code is wrong, even according to the book (online) example can not reproduce the event caused by memory leaks, the textbook is wrong?

First take a look at my code, first prepare 2 classes, one initiating event, one handling event:

 classA { Public EventEventHandler todosomething;  PublicA () {} Public voidRaiseEvent () {todosomething ( This,NewEventArgs ()); }         Public voiddelevent () {todosomething=NULL; }         Public voidPrint (stringmsg) {Console.WriteLine ("a:{0}", MSG); }    }    classB {byte[] data =NULL;  PublicBintsize) {Data=New byte[size];  for(inti =0; i < size; i++) Data[i]=0; }         Public  voidPrintA (Objectsender, EventArgs e) {((A) sender). Print ("Sender:"+sender.        GetType ()); }    }

Then, write the following method in the main program:

Static void Testinitevent (a A)        {            varnew B (1024x768);             + = b.printa;        }

This initializes an instance B of object B of 100M, and then hooks the event of object A on the method Printa of B. Normally, B is a local variable inside a method, but because the method of the B object is hooked on the event of the method parameter a object, there is no end to the life cycle of object B here, which can be later initiated by object A, and the PrintA method of B is confirmed by the invocation.

To monitor how much memory is consumed by the current test, prepare a method Getworkingset with the following code:

 Static voidGetworkingset () {using(varProcess =process.getcurrentprocess ()) {Console.WriteLine ("---------Current process name: {0}-----------", process.                ProcessName); using(varP1 =NewPerformanceCounter ("Process","working set-private", process. ProcessName))using(varP2 =NewPerformanceCounter ("Process","working Set", process. ProcessName)) {Console.WriteLine (process.                    ID); //Note divided by the number of CPUsConsole.WriteLine ("{0}{1:n} KB","Working Set (Process Class)", process. WorkingSet64/1024x768); Console.WriteLine ("{0}{1:n} KB","Working Set", process. WorkingSet64/1024x768); //process. PrivateMemorySize64 Private working set is not very accurate, probably more than 9MConsole.WriteLine ("{0}{1:n} KB","Private Working Set", p1. NextValue ()/1024x768);//P1. NextValue ()//Logger ("{0}; memory (dedicated working set) {1:n};pid:{2}; program name: {3}",//DateTime.Now, p1. NextValue ()/1024x768, process. Id.tostring (), process. ProcessName);}} Console.WriteLine ("--------------------------------------------------------");                   Console.WriteLine (); }

Below, start writing the following test code in the main program:

           Getworkingset ();             New A ();            Testinitevent (a);            Console.WriteLine ("1, press any key to start garbage collection ");            Console.readkey ();            Gc. Collect ();            Getworkingset ();

Look at the screen output:

---------Current process name: Consoleapplication1.vshost-----------4848 Working Set (Process Class) 25,260.00 KB Working Set 25,260.00 KB private working Set 8,612.00 KB--------------------------------------------------------1, Press any key to start the garbage collection---------Current process name: Consoleapplication1.vshost-----------4848 Working Set (Process Class) 135,236.00 KB Working Set 135,236.00 KB private working Set 111,256.00 KB

When the program starts running, it's just a 100M memory footprint. The current program is in the debug state of the IDE, then we run the test program directly, do not debug (Release), look at the results again:

---------Current process name: ConsoleApplication1-----------7056 Working Set (Process Class) 10,344.00 KB Working Set 10,344.00 KB private working Set 7,036.00 KB--------------------------------------------------------1, Press any key to start the garbage collection---------Current process name: ConsoleApplication1-----------7056 Working Set (Process Class) 121,460.00 KB Working Set 121,460.00 KB private working Set 109,668.00 KB--------------------------------------------------------

You can see that the memory is still not recoverable in release compilation mode.

Analyzing the above test program, we just hook an event within a single method, and the event has not been executed, followed by garbage collection, but the results show no success. This is consistent with what we've said in our textbook: After an object's event is hooked up, a memory leak can result if the hook is not lifted.

At the same time, the above results also show that the Hooked object B has not been recycled, then launch the event to test, see if the B object can continue to handle the events initiated by others, continue the above main program code:

Console.WriteLine ("2, press any key, the main object initiates the event ");            Console.readkey ();            A.raiseevent (); // The memory is not properly recycled here            Getworkingset ();

Results:

2 , press any key, the main object initiates the event a:sender:consoleapplication1.a---------Current process name: ConsoleApplication1-----------7056  Working Set (Process Class)121,576.00121,576.00109 ,672.00  KB--------------------------------------------------------

This shows that although object B is out of the range of method Testinitevent, it still survives , printing a sentence: a:sender:consoleapplication1.a

How many times can GC recycle to succeed?

We continue to try to invoke the GC on the main program:

  Console.WriteLine ("3, press any key to start garbage collection, then initiate the event again ");            Console.readkey ();            Gc. Collect ();            A.raiseevent (); // The memory is not properly recycled here            Getworkingset ();

Results:

3, press any key to start the garbage collection, and then launch the event A:sender again: consoleapplication1.a---------Current process name: ConsoleApplication1-----------7056 Working Set (Process Class) 14,424.00 KB Working Set 14,424.00 KB private working Set 2,972.00 KB--------------------------------------------------------

Sure enough, the memory is recycled, but notice that we still call the method A.raiseevent () that initiated the event after the GC executes successfully, and that the object B is still alive , but that the large amount of useless memory inside it is recycled.

Note: The result of the above code is that I write the process of the blog, while writing to test the accidental discovery of the situation, if the results are continuous execution, this is not the case, the above-mentioned code can not reclaim the success of memory.
This shows that the timing of GC memory recovery is indeed uncertain.

Continue, we write off the event, dismiss the event hook, and look at the result:

Console.WriteLine ("4, press any key to start the logoff event, then garbage collection again ");            Console.readkey ();            A.delevent ();            Gc. Collect ();            Console.WriteLine ("5, garbage collection complete ");            Getworkingset ();

Results:

4, press any key to start the logoff event, then garbage collection 5 again, garbage collection completed---------current process name: ConsoleApplication1-----------7056 Working Set (Process Class) 15,252.00 KB working Set 15,252.00 KB Private Working set 3,196.00 KB--------------------------------------------------------

The memory does not change significantly, indicating that the previous memory has indeed been successfully recycled.

To verify the previous guesses, we have the program rerun and execute continuously (release mode) to see the results of the execution:

---------Current process name: ConsoleApplication1-----------4280 Working Set (Process Class) 10,364.00 KB Working Set 10,364.00 KB private working Set 7,040.00 KB--------------------------------------------------------1, Press any key to start the garbage collection---------Current process name: ConsoleApplication1-----------4280 Working Set (Process Class) 121,456.00 KB Working Set 121,456.00 KB private working Set 109,668.00 KB--------------------------------------------------------2, press any key and the main object initiates event A:sender: consoleapplication1.a---------Current process name: ConsoleApplication1-----------4280 Working Set (Process Class) 121,572.00 KB working Set 121,572.00 KB Private Working Set 109,672.00 KB--------------------------------------------------------3, press any key to start garbage collection, and then launch event A:sender again: consoleapplication1.a---------Current process name: ConsoleApplication1-----------4280 Working Set (Process Class) 121,628.00 KB working Set 121,628.00 KB Private Working Set 109,672.00 KB--------------------------------------------------------4, press any key to start the logoff event, and then garbage collection 5 again, Garbage collection complete---------Current process name: ConsoleApplication1-----------4280 Working Set (Process Class) 19,228.00 KB Working Set 19,228.00 KB private working Set 7,272.00 KB--------------------------------------------------------
View Code

This time it does confirm that the timing of theGC's real recovery of memory is uncertain.

Compiler optimizations

Refine the previous test code, initialize only the event object and then recycle the GC to see the results:

Getworkingset ();             New A ();            Testinitevent (a); Getworkingset ();            Console.WriteLine ("4, press any key to start the logoff event, then garbage collection again ");            Console.readkey ();            A.delevent ();            Gc. Collect ();            Console.WriteLine ("5, garbage collection complete ");            Getworkingset ();            Console.readkey ();

Results:

---------Current process name: ConsoleApplication1-----------6576 Working Set (Process Class) 10,344.00 KB Working Set 10,344.00 KB private working Set 7,240.00 KB-----------------------------------------------------------------Current process name: ConsoleApplication1-----------6576 Working Set (Process Class) 121 , 500.00 KB Working Set 121,500.00 KB Private working Set 110,292.00 KB--------------------------------------------------------4, press any key to start the logoff event After garbage collection 5, garbage collection is completed---------current process name: ConsoleApplication1-----------6576 Working Set (Process Class) 19,788.00 KB Working Set 19,788.00 KB private working Set 7,900.00 KB--------------------------------------------------------

As expected, the memory reverts to normal levels after the GC.

Slightly modify the above code, just comment out the GC before the Code: A.delevent ();

Getworkingset ();             New A ();            Testinitevent (a); Getworkingset ();            Console.WriteLine ("4, press any key to start the logoff event, then garbage collection again ");            Console.readkey ();             // a.delevent ();             GC. Collect ();            Console.WriteLine ("5, garbage collection complete ");            Getworkingset ();            Console.readkey ();

Look at the results again:

---------Current process name: ConsoleApplication1-----------4424 Working Set (Process Class) 10,308.00 KB Working Set 10,308.00 KB private working Set 7,040.00 KB-----------------------------------------------------------------Current process name: ConsoleApplication1-----------4424 Working Set (Process Class) 121 , 256.00 KB Working set 121,256.00 KB Private working Set 7,592.00 KB--------------------------------------------------------4, press any key to start the logoff event, After garbage collection 5 again, the garbage collection is complete---------current process name: ConsoleApplication1-----------4424 Working Set (Process Class) 19,436.00 KB Working Set 19,436.00 KB private working Set 7,600.00 KB--------------------------------------------------------

Big surprise: There is not a lot of memory consumption situation!

There seems to be only one possibility:

Object A does not have code such as an action event before the GC reclaims the memory, so it is very clear that the event code before object A is no longer valid, and that the related object B can be in testinitevent (a); The method call is immediately recycled, so you see the test results now.

If it's not Release compilation mode optimization, let's take a look at the results of the IDE Debug or Debug compilation mode (the previous code doesn't make any changes):

---------Current process name: Consoleapplication1.vshost-----------8260 Working Set (Process Class) 25,148.00 KB Working Set 25,148.00 KB private working Set 9,816.00 KB-----------------------------------------------------------------Current process name: Consoleapplication1.vshost-----------8260 Working Set (process Class) 136,048.00 KB Working Set 136,048.00 KB Private working Set 112,888.00 KB--------------------------------------------------------4, Press any key to start the logoff event, then garbage collection 5 again, garbage collection completed---------current process name: Consoleapplication1.vshost-----------8260 Working Set (Process Class) 136,692.00 KB working Set 136,692.00 KB Private Working set 112,892.00 KB--------------------------------------------------------


This time, although GC garbage collection was still called, it didn't actually work immediately, and the memory was still more than 100 m.

Finally, after we launch the event hooks, we immediately dismiss the event hooks and then look at the results in debug mode, just to modify the following code one place:

     Static void Testinitevent (a A)        {            varnew B (1024x768);             + = B.printa            ; //            A.todosomething-= b.printa;        }

Then look at the results of the execution in debug mode:

---------Current process name: Consoleapplication1.vshost-----------8652 Working Set (Process Class) 26,344.00 KB Working Set 26,344.00 KB private working Set 9,452.00 KB-----------------------------------------------------------------Current process name: Consoleapplication1.vshost-----------8652 Working Set (process Class) 135,628.00 KB Working Set 135,628.00 KB Private working Set 10,008.00 KB--------------------------------------------------------4, Press any key to start the logoff event, then garbage collection 5 again, garbage collection completed---------current process name: Consoleapplication1.vshost-----------8652 Working Set (Process Class) 33,768.00 KB working Set 33,768.00 KB Private Working set 10,008.00 KB--------------------------------------------------------

As expected, memory consumption does not increase, so it is meaningless to call GC to reclaim memory at this time.

Summarize

It is true that a memory leak can occur if the event is not unblocked after use.

And the timing of GC memory recovery is indeed uncertain, so the GC is not a lifeline, and the best practice is to use the event immediately to dismiss the event hook.

If you forget this thing, please do not forget to publish the program, use release compilation mode!

Release compilation mode, whether the event will cause a memory leak problem preliminary study

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.