C# 内存泄露

摘要:
2.对于内存泄漏,让我们将代码更改为{Microsoft.Win32的publicclassProgram{staticvoidShowMemory(){Console.WriteLine;}staticvoid Main{ShowMemory()。系统事件。DisplaySettingsChanged+=newEventHandler;气相色谱法。Collect();气相色谱法。等待等待等待定案();气相色谱法。Collect();ShowMemory();}安慰ReadKey();}}PublicclassMyMethod{byte[]m_ExtraMemory=newbyte[1024*1024*12];publicvoid SystemEvents_DisplaySettingsChanged{}}输出结果如下:从输出结果来看,GC无法正常回收内存。另一个需要注意的是Singleton单例模式实现的类。它们也有很长的静态生命周期。注意引用链,以及你的类是否被它引用。如果它在引用链上,它会泄漏内存。
一、事件引起的内存泄露

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

  上述代码输出如下:

  C# 内存泄露第3张 

  从输出来看,内存被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){ }
    }
复制代码

  输出结果如下:

  C# 内存泄露第6张

  从输出结果来看,内存已不能被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);
        }
    }
复制代码

  输出如下:

  C# 内存泄露第3张

  增加了一个Dispose来实现 "-="功能就OK了。

二、注意静态、单例

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

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

免责声明:文章转载自《C# 内存泄露》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇第五章 Python 函数(一)学习信息学奥赛,这五大的网站别忘了收藏下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

Vue 引入 svg文件

在图标显示中,通常使用font真棒图标库,它很简单,只需下载和导入即可。重要的显示:内联块;}2.在src目录下,添加一个名为icons的文件夹,并在icons文件夹下添加索引。js文件和svg文件夹,其中svg文件存储在svg文件夹中。...

PCL点云分割(2)

点云的分割是我想做的机器人手臂捕捉的一个非常重要的部分,因此首先要了解,如果我使用点云库来处理我用kinect获得的点云数据,这个例程也是由我自己慢慢修改程序并结合官方API的解释来实现的。如果我直接更改源程序,由于数据类型、头文件和其他原因,其中的许多细节可能无法编译,我们将很难找出错误。首先,让我们看看我自己设定的场景。然后我使用Kinect获取数据并观...

nginx重启

方法二:在启动命令-c前加-t2、重启Nginx服务方法一:进入nginx可执行目录sbin下,输入命令./nginx-sreload即可方法二:查找当前nginx进程号,然后输入命令:kill-HUP进程号实现重启nginx服务...

开源BI分析工具Metabase配置与完全使用手册

文章目录简介安装初始配置数据分析简单查询创建场景创建集合和仪表盘自定义查询原生查询sql变量动态sql片段管理员操作添加数据库连接oracle成员管理邀请新成员权限配置数据权限文件夹权限邮箱配置定时任务简介Metabase是一个免费的BI分析工具,可以帮助你把数据库中的数据更好的呈现给更多人,通过建立一个”查询“来提炼数据,再以图形化的方式做展示。上手简单,...

Windows怎么从命令行下载文件

具体步骤如下:1.打开cmd。exeWin+R或git的bush接口。2.启动powershell。2.在命令行中输入startpowershell以启动powershell。3.下载操作。1.在powershell中输入$client=newobjectSystem.Net.WebClient3.2。exe文件,然后输入$client。下载文件('X','...

PB各对象常用事件

1.触发窗口中事件名称的时间01.在激活窗口之前激活触发器02。单击触发器03.Close触发器04.CloseQuery在窗口被清除或关闭时触发。...