Net 内存泄露
2016-01-06 16:47
239 查看
Net 内存泄露
我们经常会写EventHandler += AFunction; 如果没有手动注销这个Event handler类似:EventHandler –= AFunction 有可能会发生内存泄露。
上述代码输出如下:
从输出来看,内存被GC正常地回收,没有问题。
2、内存泄露的情况
我们来将代码改动一下
输出结果如下:
从输出结果来看,内存已不能被GC正常回收。为什么会出现这种情况呢?我们来看看Microsoft.Win32.SystemEvents.DisplaySettingsChanged的源代码(省略前后部分):
为什么会有差别,根本区别在于后者有个SystemEvents.DisplaySettingsChanged事件,而这个事件是静态的。
3、释放资源
如果我们希望释放资源,则我们需要在某个地方实现-=AFunction操作
输出如下:
增加了一个Dispose来实现 "-="功能就OK了。
另外一个要注意的是Singleton单例模式实现的类,他们也是static的生命周期很长,要注意引用链,你的类是否被它引用上,如果在它的引用链上,就内存泄露了。
参考:/article/4698583.html
一、事件引起的内存泄露
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的生命周期很长,要注意引用链,你的类是否被它引用上,如果在它的引用链上,就内存泄露了。
参考:/article/4698583.html
相关文章推荐
- 第五章 HashMap源码解析
- lesson2: Python:for语句简单应用
- UILabel 的使用,属性详解
- codevs 1155 金明的预算方案
- 关于普通端口映射的原理
- 关于VS中LNK1120与errorLNK2019问题
- Maven介绍与使用
- [bug] Field 'id' doesn't have a default value
- 3.1.4_Lists(列表)
- UITableView - 重用机制
- unsafe的使用报错
- mysql DECLARE CONTINUE HANDLER FOR NOT FOUND
- 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解
- CS0433: 类型“BasePage”同一时候存在于“c:\Windows\Microsoft.NETxxxxxxxxxxxxxxxx
- play(1) 第一个简单的应用
- 伪静态-URLRewrite 详解
- 7.配置zabbix报警
- 无线与PC的区别
- CentOS开机启动脚本的顺序
- 一个半圆形拖动条