zoukankan      html  css  js  c++  java
  • Net 内存泄露

    Net 内存泄露

    一、事件引起的内存泄露

      1、不手动注销事件也不发生内存泄露的情况

      我们经常会写EventHandler += AFunction; 如果没有手动注销这个Event handler类似:EventHandler –= 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++)
                {
                    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());
            }
        }
    复制代码

      上述代码输出如下:

       

      从输出来看,内存被GC正常地回收,没有问题。

      2、内存泄露的情况

      我们来将代码改动一下

    复制代码
        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){ }
        }
    复制代码

      输出结果如下:

      

      从输出结果来看,内存已不能被GC正常回收。为什么会出现这种情况呢?我们来看看Microsoft.Win32.SystemEvents.DisplaySettingsChanged的源代码(省略前后部分):

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

      为什么会有差别,根本区别在于后者有个SystemEvents.DisplaySettingsChanged事件,而这个事件是静态的。

      3、释放资源

      如果我们希望释放资源,则我们需要在某个地方实现-=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了。

    二、注意静态、单例

       静态对象生命周期很长,永远不会被GC回收,一旦被他给引用上了,那就不可能释放了。上面的例子就是被静态的DisplaySettingsChanged 引用导致不能被回收。

      另外一个要注意的是Singleton单例模式实现的类,他们也是static的生命周期很长,要注意引用链,你的类是否被它引用上,如果在它的引用链上,就内存泄露了。

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

  • 相关阅读:
    第 17 章 责任链模式【Chain of Responsibility Pattern】
    第 16 章 观察者模式【Observer Pattern】
    第 15 章 组合模式【Composite Pattern】
    第 14 章 迭代器模式【Iterator Pattern】
    第 13 章 装饰模式【Decorator Pattern】
    第 12 章 命令模式【Command Pattern】
    第 11 章 桥梁模式【Bridge Pattern】
    第 10 章 建造者模式【Builder Pattern】
    编写高质量代码改善C#程序的157个建议——导航开篇
    C#实现简易ajax调用后台方法
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5106196.html
Copyright © 2011-2022 走看看