.Net 内存泄露

发布日期:2018-02-09    浏览次数:518

一、事件引起的内存泄露

  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

本文网址:https://www.wyxxw.cn/blog-detail-2-6-259.html

返回列表

非特殊说明,本文版权归原作者所有,转载请注明出处

提示:本站所有资源仅供学习与参考,请勿用于商业用途。图片来自互联网~如侵犯您的权益,请联系QQ:1067507709.

提示:转载请注明来自:http://www.cnblogs.com/kissdodog/p/3672460.html 。 转载人:momo