Analysis of memory leaks caused by events in. Net

Source: Internet
Author: User

Series Theme: The evolution of message-based software architecture model

In the WinForm and ASP. NET era, events are heavily applied in code that interacts with the UI and the background. Look at the following code:

                private void Bindevent ()        {            var btn = new Button ();            Btn. Click + = Btn_click;        }        void Btn_click (object sender, EventArgs e)        {            MessageBox.Show ("click");        }

Can this usage cause a memory leak? Why do we always write code like this never pays attention to a memory leak? After the analysis of the reasons and then to answer this question.

To test the reason, we first write an Eventpublisher class to publish the event:

    public class Eventpublisher    {public        static int Count;        public event eventhandler<publishereventargs> onsomething;        Public Eventpublisher ()        {            interlocked.increment (ref Count);        }        public void triggersomething ()        {            raiseonsomething (new Publishereventargs (Count));        }        protected void raiseonsomething (Publishereventargs e)        {            eventhandler<publishereventargs> handler = onsomething;            if (handler! = NULL) handler (this, e);        }        ~eventpublisher ()        {            interlocked.decrement (ref Count);        }    }

This class provides an event onsomething, and the variable count is incremented and decremented separately in constructors and destructors. The number of count reflects the number of instances of eventpublisher in memory.

Write a subscriber to subscribe to this event:

    public class subscriber    {public        string Text {get; set;}        Public list<stringbuilder> List = new list<stringbuilder> ();        public static int Count;        Public Subscriber ()        {            interlocked.increment (ref Count);            for (int i = 0; i < i++)            {                list.add (new StringBuilder (1024x768));}        }        public void ShowMessage (object sender, Publishereventargs e)        {            Text = string. Format ("There is {0} publisher in memory", E.publisherreferencecount);        }        ~subscriber ()        {            interlocked.decrement (ref Count);        }    }

Subscriber also uses count to reflect the number of instances in memory, and we use StringBuilder in our constructors to open up the size of the 1000*1024size to make it easier for us to observe memory usage.

In the final step, write a simple WinForm program and write the test code in a button's Click event:

               private void Btnstartshorttimepublishertest_click (object sender, EventArgs e)        {for            (int i = 0; i <; i++) 
   {                var publisher = new Eventpublisher ();                Publisher. Onsomething + = new Subscriber (). ShowMessage;                Publisher. Triggersomething ();            }            MessageBox.Show (String. Format ("There is {0} publishers in memory, {1} subscribers in memory", Eventpublisher.count, Subscriber.count));        }

The code in the For loop is a trivial event calling code, we bind the ShowMessage method in the Subscriber instance to the Onsomething event of the Publisher object, and we loop 100 times to observe the memory changes.

The results of the implementation are as follows:

The number of Publisher and Subscriber is 3, which does not mean that a memory leak has occurred, but is not completely recycled. Each publisher is considered useless after it has been out of the for loop and is properly recycled. Subscriber, the observer registered above, can also be recovered correctly.

Put a button again and write the following test code in the click:

                private void Btnstartlongtimepublisher_click (object sender, EventArgs e)        {for            (int i = 0; i <; i++)            { C4/>var publisher = new Eventpublisher ();                Publisher. Onsomething + = new Subscriber (). ShowMessage;                Publisher. Triggersomething ();                Longlivedeventpublishers.add (publisher);            }            MessageBox.Show (String. Format ("There is {0} publishers in memory, {1} subscribers in memory", Eventpublisher.count,subscriber.count));        }

The difference in this for loop is that we keep publisher in a list container so that 100 publisher cannot be garbage collected. The results of this implementation are as follows:

We see that 100 subscribers are all stored in memory. If you look at the memory usage in the Explorer, you can also see that the memory has suddenly risen by hundreds of trillion and will not be reduced any more.

Consider the following scenario:

    public class Runner    {        private longtimeservice _service;        Public Runner ()        {             _service = new Longtimeservice ();                    }        public void Run ()        {            _service. somethingupdated + = (o, e) + = {/*do some thing*/};            _service. somethingupdated + = (o, e) + = {/*do some thing*/};            _service. somethingupdated + = (o, e) + = {/*do some thing*/};            _service. somethingupdated + = (o, e) + = {/*do some thing*/};}    

Longtimeservice is a long-running service that is never destroyed, which will result in all observers registered on the Somethingupdated event not being recycled. When a large number of observers keep registering on the somethingupdated, the memory leaks.

These three tests illustrate a scenario that causes an event memory leak: The Observer cannot be reclaimed by memory when the Observer is registered on an event topic that has a life cycle longer than its own.

The workaround is to display the invoke-= symbol on the event.

Then look back at the question that started: memory leaks occur when a button's Click event is used?

Btn. Click + = Btn_click;

Who is the observer? The owner of the Btn_click method, which is the form instance.

Who's the subject? Instance of button BTN

When does the theme btn be destroyed? When the form instance is destroyed.

When the form is destroyed, both BTN and its observers are destroyed. Unless the form is never destroyed, and a large number of observers continue to register in the BTN. A memory leak can occur on click, but this scenario is rare. So when we develop WinForm or ASP, we generally don't care about memory leaks.

Analysis of memory leaks caused by events in. Net

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.