.NET內存泄漏(之 靜態事件)

1、事件引發的內存泄露

  一、不手動註銷事件也不發生內存泄露的狀況html

  咱們常常會寫EventHandler += AFunction; 若是沒有手動註銷這個Event handler相似:EventHandler –= AFunction 有可能會發生內存泄露。post

複製代碼
    public class Program
    {
        static void ShowMemory()
        {
            Console.WriteLine("共用內存:{0}M", GC.GetTotalMemory(true) / 1024 / 1024);
        }

        static void Main(string[] args)
        {
            ShowMemory();
            for (int i = 0; i < 5; i++)
            {
                EventSample es = new EventSample();
                es.ShowComplete += es.MyEventHandler;
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                ShowMemory();
            }
            Console.ReadKey();
        }
    }

    public class EventSample
    {
        byte[] m_ExtraMemory = new byte[1024 * 1024 * 12];

        //定義一個事件
        public event EventHandler ShowComplete;

        //觸發事件
        public void OnShowComplete()
        {
            //判斷是否綁定了事件處理方法,null表示沒有事件處理方法
            if (ShowComplete != null)
            {
                //像調用方法同樣觸發事件
                ShowComplete(this, new EventArgs());
            }
        }

        //事件處理方法
        public void MyEventHandler(object sender, EventArgs e)
        {
            Console.WriteLine("誰觸發了我?" + sender.ToString());
        }
    }
複製代碼

  上述代碼輸出以下:this

   

  從輸出來看,內存被GC正常地回收,沒有問題。spa

  二、內存泄露的狀況3d

  咱們來將代碼改動一下code

複製代碼
    public class Program
    {
        static void ShowMemory()
        {
            Console.WriteLine("共用內存:{0}M", GC.GetTotalMemory(true) / 1024 / 1024);
        }

        static void Main(string[] args)
        {
            ShowMemory();
            for (int i = 0; i < 5; i++)
            {
                Microsoft.Win32.SystemEvents.DisplaySettingsChanged += new EventHandler(new MyMethod().SystemEvents_DisplaySettingsChanged);
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                ShowMemory();
            }
            Console.ReadKey();
        }
    }

    public class MyMethod
    {
        byte[] m_ExtraMemory = new byte[1024 * 1024 * 12];
        public void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e){ }
    }
複製代碼

  輸出結果以下:htm

  

  從輸出結果來看,內存已不能被GC正常回收。爲何會出現這種狀況呢?咱們來看看Microsoft.Win32.SystemEvents.DisplaySettingsChanged的源代碼(省略先後部分):對象

    public sealed class SystemEvents
    {
        ... ...
        public static event EventHandler DisplaySettingsChanged
        ... ...
    }

  爲何會有差異,根本區別在於後者有個SystemEvents.DisplaySettingsChanged事件,而這個事件是靜態的。blog

  三、釋放資源生命週期

  若是咱們但願釋放資源,則咱們須要在某個地方實現-=AFunction操做

複製代碼
    public class Program
    {
        static void ShowMemory()
        {
            Console.WriteLine("共用內存:{0}M", GC.GetTotalMemory(true) / 1024 / 1024);
        }

        static void Main(string[] args)
        {
            ShowMemory();
            for (int i = 0; i < 5; i++)
            {
                using (MyMethod myMethod = new MyMethod())
                {
                    Microsoft.Win32.SystemEvents.DisplaySettingsChanged += new EventHandler(myMethod.SystemEvents_DisplaySettingsChanged);
                }
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                ShowMemory();
            }
            Console.ReadKey();
        }
    }

    public class MyMethod : IDisposable
    {
        byte[] m_ExtraMemory = new byte[1024 * 1024 * 12];
        public void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e) { }

        public void Dispose() { Microsoft.Win32.SystemEvents.DisplaySettingsChanged -= new EventHandler(SystemEvents_DisplaySettingsChanged); }
    }
複製代碼

  輸出以下:

  

  增長了一個Dispose來實現 "-="功能就OK了。

2、注意靜態、單例

  靜態對象生命週期很長,永遠不會被GC回收,一旦被他給引用上了,那就不可能釋放了。上面的例子就是被靜態的DisplaySettingsChanged 引用致使不能被回收。

  另一個要注意的是Singleton單例模式實現的類,他們也是static的生命週期很長,要注意引用鏈,你的類是否被它引用上,若是在它的引用鏈上,就內存泄露了。

 

 

參考:http://www.cnblogs.com/Mainz/archive/2011/09/10/2173162.html

http://www.cnblogs.com/kissdodog/p/3672460.html

http://www.cnblogs.com/artech/archive/2010/10/18/CLR_Memory_Mgt_01.html

http://www.cnblogs.com/artech/archive/2010/10/20/CLR_Memory_Mgt_02.html

相關文章
相關標籤/搜索