一、事件引起的内存泄露

  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内存泄漏(之 静态事件)的更多相关文章

  1. .NET中常见的内存泄漏和解决办法

    在.NET中,虽然CLR的GC垃圾回收器帮我们自动回收托管堆对象,释放内存,最大程度避免了"内存泄漏"(应用程序所占用的内存没有得到及时释放),但.NET应用程序"内存泄 ...

  2. 说说JVM原理?内存泄漏与溢出的区别?何时产生内存泄漏?

    1.JVM原理 JVM是Java Virtual Machine(Java虚拟机)的缩写,它是整个java实现跨平台的最核心的部分,所有的Java程序会首先被编译为.class的类文件,这种类文件可以 ...

  3. Release编译模式下,事件是否会引起内存泄漏问题初步研究

    题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...

  4. Android内存优化10 内存泄漏常见情况1 静态泄漏

    1,内存泄漏到本质是该释放的对象被持久化的对象引用了,造成持久化的常见情况有1,静态持久化 2,线程持久化 线程持久化 因为存活的线程是有dvk虚拟久直接持有,所以存活的线程都是持久化的 内存泄漏1: ...

  5. PerfView专题 (第八篇):洞察 C# 内存泄漏之寻找静态变量名和GC模式

    一:背景 这篇我们来聊一下 PerfView 在协助 WinDbg 分析 Dump 过程中的两个超实用技巧,可能会帮助我们快速定位最后的问题,主要有如下两块: 洞察内存泄漏中的静态大集合变量名. 验证 ...

  6. .net中事件引起的内存泄漏分析

    系列主题:基于消息的软件架构模型演变 在Winform和Asp.net时代,事件被大量的应用在UI和后台交互的代码中.看下面的代码: private void BindEvent() { var bt ...

  7. .NET 垃圾回收与内存泄漏

    > 前言相信大家一定听过,看过甚至遇到过内存泄漏.在 .NET 平台也一定知道有垃圾回收器,它可以让开发人员不必担心内存的释放问题,因为它会自定管理内存.但是在 .NET 平台下进行编程,绝对不 ...

  8. Java提高篇—— 简单介绍Java 的内存泄漏

    java最明显的一个优势就是它的内存管理机制.你只需简单创建对象,java的垃圾回收机制负责分配和释放内存.然而情况并不像想像的那么简单,因为在Java应用中经常发生内存泄漏. 本教程演示了什么是内存 ...

  9. 浅析c#内存泄漏

    一直以来都对内存泄露和内存溢出理解的不是很深刻.在网上看到了几篇文章,于是整理了一下自己对内存泄露和内存溢出的理解. 一.概念 内存溢出:指程序在运行的过程中,程序对内存的需求超过了超过了计算机分配给 ...

  10. UWP开发入门(十三)——用Diagnostic Tool检查内存泄漏

    因为.NET的垃圾回收机制相当完善,通常情况下我们是不需要关心内存泄漏的.问题人一但傻起来,连自己都会害怕,几个页面跳啊跳的,内存蹭蹭的往上涨,拉都拉不住.这种时候我们就需要冷静下来,泡一杯热巧克力. ...

随机推荐

  1. WPFToolkit DataGrid 使用介绍zz

      首先:这版本需要.NetFrameWork SP1的支持 WPF Toolkit - February 2010 Release 下载地址:http://wpf.codeplex.com/rele ...

  2. 学习DRF之前

    在学习DRF之前~我们要先复习一些知识点~~ FBV和CBV的区别 学习Django的时候~我们已经了解过CBV以及FBV 什么是FBV和CBV呢~~ FBV 基于函数的视图 CBV 基于类的视图 也 ...

  3. input输入框限制20个字符,十个汉字

    英文和数字为一个字符,汉字为两个字符 在 Web 开发中,经常要对表单元素的输入进行限制,比如说不允许输入特殊字符,标点.通常我们会监听 input 事件: inputElement.addEvent ...

  4. BZOJ.3170.[TJOI2013]松鼠聚会(切比雪夫距离转曼哈顿距离)

    题目链接 将原坐标系每个点的坐标\((x,y)\)变为\((x+y,x-y)\),则原坐标系中的曼哈顿距离等于新坐标系中的切比雪夫距离. 反过来,将原坐标系每个点的坐标\((x,y)\)变为\((\f ...

  5. 2017-10-5-Python

    想学习Python很长时间了,工作中使用Python脚本解决问题真的很爽. 插入一张Python的py文件常见的结构图: if __name__ =="__main__" 这条语句 ...

  6. 2546 ACM 01背包

    题目http://acm.hdu.edu.cn/showproblem.php?pid=2546 思路:再01背包的问题上稍作修改 如何满足 :卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购 ...

  7. IntelliJ IDEA classpath包含哪些文件夹以及如何把文件(夹)添加到classpath下

    在IDEA中,标为蓝色的文件夹被认定为包含在classpath中,例如上图中的resources.src文件夹.把文件位置以"classpath:applicationContext.xml ...

  8. 32位系统和x86的关系?

    32位操作系统针对32位CPU设计,cpu的位是指一次性可处理的数据量是多少,也等于寻址空间的大小或是通用寄存器的大小,一般数据总线的宽度也和cpu位数相同,但也有例外(如8088数据总线宽度为8然而 ...

  9. 线段树入门&lazy思想

    线段树将区间分成若干个子区间,子区间又继续分,直到区间为一个点(区间左值等于右值) 对于父区间[a,b],其子区间为[a,(a+b)/2]和[(a+b)/2+1,b] 用于求区间的值,如区间最值.区间 ...

  10. python之封装

    封装的主要原因是保护隐私,隔离复杂度 封装分为两个层面: 第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称精简,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种分装 ...