C# 内存泄露
一、事件引起的内存泄露
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的生命周期很长,要注意引用链,你的类是否被它引用上,如果在它的引用链上,就内存泄露了。
C# 内存泄露的更多相关文章
- java: web应用中不经意的内存泄露
前面有一篇讲解如何在spring mvc web应用中一启动就执行某些逻辑,今天无意发现如果使用不当,很容易引起内存泄露,测试代码如下: 1.定义一个类App package com.cnblogs. ...
- 查看w3wp进程占用的内存及.NET内存泄露,死锁分析
一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- 基于HTML5的WebGL应用内存泄露分析
上篇(http://www.hightopo.com/blog/194.html)我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动, ...
- android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!
1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayo ...
- js内存泄露的几种情况详细探讨
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束.在C++中,因为是手动管理内存,内存泄露是经常出现的事情.而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使 ...
- 使用Xcode7的Instruments检测解决iOS内存泄露
文/笨笨的糯糯(简书作者)原文链接:http://www.jianshu.com/p/0837331875f0著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 作为一名iOS开发攻城狮, ...
- 使用Visual Leak Detector for Visual C++ 捕捉内存泄露
什么是内存泄漏? 内存泄漏(memory leak),指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段 ...
- java内存溢出和内存泄露
虽然jvm可以通过GC自动回收无用的内存,但是代码不好的话仍然存在内存溢出的风险. 最近在网上搜集了一些资料,现整理如下: —————————————————————————————————————— ...
- java内存泄露
上一篇提到的是java垃圾回收,今天谈谈java的内存泄露. 首先谈下java的内存管理机制: 在Java程序中,我们通常使用new为对象分配内存,而这些内存空间都在堆(Heap)上. public ...
随机推荐
- HOJ 1096 Divided Product (DFS)
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Given two positive integers N and M, please divide N into sev ...
- hdu 5612 Baby Ming and Matrix games(dfs暴力)
Problem Description These few days, Baby Ming is addicted to playing a matrix game. Given a n∗m matr ...
- Python 协程(gevent)
协程,又叫微线程,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈.因此: 协程能保留上 ...
- 用CSS/CSS3 实现 水平居中和垂直居中的完整攻略
水平居中:行内元素解决方案 只需要把行内元素包裹在一个属性display为block的父层元素中,并且把父层元素添加如下属性即可: .parent { text-align:center; } 水 ...
- php创建带logo的二维码
<?php /** php使用二维码 **/ class MyQrcode{ const SIZE = 150; const LEVEL = "L"; const MARGI ...
- boost 定时器.
#include <iostream> #include <boost/asio.hpp> int main() { boost::asio::io_service io; b ...
- vue-resource插件使用
本文的主要内容如下: 介绍vue-resource的特点 介绍vue-resource的基本使用方法 基于this.$http的增删查改示例 基于this.$resource的增删查改示例 基于int ...
- Docker搭建私有仓库
1,下载仓库镜像. docker pull registry //主要用于搭建私有仓库的. 2,将宿主机端口映射到容器中去,容器的5000端口是不能更改的. docker run -d -p ...
- 关于position和float的用法!
我要说的是这部分的切图, 先说一下为什么要用到position 看我的截图, 应该知道这块的组成是有两部分, 但中间那个绿圈中, 组成的两个部分有重叠的, 这时候, 可能会想用float, 但floa ...
- 【js】判断设备类型,访问相应的网站
引入 function uaredirect(f) { try { if (document.getElementById("bdmark") != null) { return ...