.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
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
.NET内存泄漏(之 静态事件)的更多相关文章
- .NET中常见的内存泄漏和解决办法
在.NET中,虽然CLR的GC垃圾回收器帮我们自动回收托管堆对象,释放内存,最大程度避免了"内存泄漏"(应用程序所占用的内存没有得到及时释放),但.NET应用程序"内存泄 ...
- 说说JVM原理?内存泄漏与溢出的区别?何时产生内存泄漏?
1.JVM原理 JVM是Java Virtual Machine(Java虚拟机)的缩写,它是整个java实现跨平台的最核心的部分,所有的Java程序会首先被编译为.class的类文件,这种类文件可以 ...
- Release编译模式下,事件是否会引起内存泄漏问题初步研究
题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...
- Android内存优化10 内存泄漏常见情况1 静态泄漏
1,内存泄漏到本质是该释放的对象被持久化的对象引用了,造成持久化的常见情况有1,静态持久化 2,线程持久化 线程持久化 因为存活的线程是有dvk虚拟久直接持有,所以存活的线程都是持久化的 内存泄漏1: ...
- PerfView专题 (第八篇):洞察 C# 内存泄漏之寻找静态变量名和GC模式
一:背景 这篇我们来聊一下 PerfView 在协助 WinDbg 分析 Dump 过程中的两个超实用技巧,可能会帮助我们快速定位最后的问题,主要有如下两块: 洞察内存泄漏中的静态大集合变量名. 验证 ...
- .net中事件引起的内存泄漏分析
系列主题:基于消息的软件架构模型演变 在Winform和Asp.net时代,事件被大量的应用在UI和后台交互的代码中.看下面的代码: private void BindEvent() { var bt ...
- .NET 垃圾回收与内存泄漏
> 前言相信大家一定听过,看过甚至遇到过内存泄漏.在 .NET 平台也一定知道有垃圾回收器,它可以让开发人员不必担心内存的释放问题,因为它会自定管理内存.但是在 .NET 平台下进行编程,绝对不 ...
- Java提高篇—— 简单介绍Java 的内存泄漏
java最明显的一个优势就是它的内存管理机制.你只需简单创建对象,java的垃圾回收机制负责分配和释放内存.然而情况并不像想像的那么简单,因为在Java应用中经常发生内存泄漏. 本教程演示了什么是内存 ...
- 浅析c#内存泄漏
一直以来都对内存泄露和内存溢出理解的不是很深刻.在网上看到了几篇文章,于是整理了一下自己对内存泄露和内存溢出的理解. 一.概念 内存溢出:指程序在运行的过程中,程序对内存的需求超过了超过了计算机分配给 ...
- UWP开发入门(十三)——用Diagnostic Tool检查内存泄漏
因为.NET的垃圾回收机制相当完善,通常情况下我们是不需要关心内存泄漏的.问题人一但傻起来,连自己都会害怕,几个页面跳啊跳的,内存蹭蹭的往上涨,拉都拉不住.这种时候我们就需要冷静下来,泡一杯热巧克力. ...
随机推荐
- puppeteer 安装失败的解决方案
你应该也是在玩puppeteer,所以才会来到这里寻找答案,开始正文…… 安装时遇到 ERROR: Failed to download Chromium r515411! Set "PUP ...
- [Win] Win8权限机制导致R安装包失败
在Rstudio安装tidyselect的时候,提示 ERROR: compilation failed for package ‘tidyselect’ 搜了一下,在github上找到tidysel ...
- 英语口语练习系列-C31-图书-谈论事物-白雪歌送武判官归京
book your favorite book a story in your childhood a character in film or TV 词汇 含义 备注 trend 趋势 indivi ...
- Android应用程序结构
综述:Android应用程序包含哪些部分? assets 可以出发一些随程序打包的文件,应用程序运行时可以动态读取到这些文件的内容. 如果使用到webview加载本地网页的功能,所有网页相关的文件都存 ...
- [HNOI2017/AHOI2017]影魔
Description: 奈文摩尔有 \(n\) 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 \(1\) 到 \(n\).第 \(i\) 个灵魂的战斗力为 \(k_i\),灵魂们以点对的形 ...
- [ZJOI2012]波浪
Description: L = | P2 – P1 | + | P3 – P2 | + - + | PN – PN-1 | 给你一个N和M,问:随机一个1-N的排列,它的波动强度(L)不小于M的概率 ...
- iOS自动布局的学习
Autolayout: 最重要的两个概念: 约束:对控件位置和大小的限定条件 参照:对控件设置的约束是相对于哪一个视图而言的 自动布局的核心计算公式: obj1.property1 =(obj2.pr ...
- JAVA分词包
自然语言处理 中文分词 词性标注 命名实体识别 依存句法分析 关键词提取 自动摘要 短语提取 拼音 简繁转换 http://www.hankcs.com/nlp/ https://github.com ...
- UIButton高亮状态卡顿
童鞋们有么有遇到过一个tableview或者是scrollview上放置一个button然后点击button,但是button的高亮状态切换不过来呢? 解决方案: 新建一个类继承自UITableVie ...
- C#_02.13_基础四_.NET方法
C#_02.13_基础四_.NET方法 一.方法概述: 方法是一块具有名称的代码.可以通过方法进行调用而在别的地方执行,也可以把数据传入方法并接受数据输出. 二.方法的结构: 方法头 AND 方法 ...