net 内存泄露和内存溢出
一直以来都对内存泄露和内存溢出理解的不是很深刻。在网上看到了几篇文章,于是整理了一下自己对内存泄露和内存溢出的理解。
一.概念
内存溢出:指程序在运行的过程中,程序对内存的需求超过了超过了计算机分配给程序的内存,从而造成“Out of memory”之类的错误,使程序不能正常运行。
造成内存溢出有几种情况:
1.计算机本身的内存小,当同时运行多个软件时,计算机得内存不够用从而造成内存溢出。对于这种情况,只能增加计算机内存来解决。
2.软件程序的问题,程序在运行时没能及时释放不用的内存,造成使用的内存越来越大从而造成内存溢出。对于这种情况,可以修改程序的代码来解决。
内存泄露:内存泄漏指由于疏忽或错误造成程序不能释放或不能及时释放已经不再使用的内存的情况,是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存不能回收和不能及时回收。当程序不能释放的内存越来越多是就会造成程序的性能下降或出现内存溢出的错误。
二、内存泄露检测工具:
1. SciTech Software AB .NET Memory Profiler-找到内存泄漏并优化内存使用针对C#,VB.Net,或其它.Net程序。
2. YourKit .NET & Java Profiler-业界领先的Java和.NET程序性能分析工具。
3. AutomatedQA AQTime-AutomatedQA的获奖产品performance profiling和memory
debugging工具集的下一代替换产品,支持Microsoft, Borland, Intel, Compaq 和
GNU编译器。可以为.NET和Windows程序生成全面细致的报告,从而帮助您轻松隔离并排除代码中含有的性能问题和内存/资源泄露问题。支
持.Net 1.0,1.1,2.0,3.0和Windows 32/64位应用程序。
4. JavaScript Memory Leak Detector-微软全球产品开发欧洲团队(Global Product
Development- Europe team, GPDE)
发布的一款调试工具,用来探测JavaScript代码中的内存泄漏,运行为IE系列的一个插件。
5.使用LoadRunner,使用方法http://www.cnblogs.com/mayingbao/archive/2007/12/20/1006818.html
6.使用 .Net Memory Profiler 工具,使用方法见:http://lzy.iteye.com/blog/344317
7.在单元测试时,在代码中检测,如.net 下 使用Console.WriteLine("Total memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true));代码可以查看当前使用的内存。
二、导致内存泄露的常见情况及解决方法:
1.未退订的事件
是否没有手动注销事件就会造成内存泄露,我们先看这个问题
- class TestClassHasEvent
- {
- public delegate void TestEventHandler(object sender, EventArgs e);
- public event TestEventHandler YourEvent;
- protected void OnYourEvent(EventArgs e)
- {
- if (YourEvent != null) YourEvent(this, e);
- }
- }
- class TestListener
- {
- byte[] m_ExtraMemory = new byte[1000000];
- private TestClassHasEvent _inject;
- public TestListener(TestClassHasEvent inject)
- {
- _inject = inject;
- _inject.YourEvent += new TestClassHasEvent.TestEventHandler(_inject_YourEvent);
- }
- void _inject_YourEvent(object sender, EventArgs e)
- {
- }
- }
- class Program
- {
- static void DisplayMemory()
- {
- Console.WriteLine("Total memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true));
- }
- static void Main()
- {
- DisplayMemory();
- Console.WriteLine();
- for (int i = 0; i < 5; i++)
- {
- Console.WriteLine("--- New Listener #{0} ---", i + 1);
- var listener = new TestListener(new TestClassHasEvent());
- ////listener = null; //可有可无
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
- DisplayMemory();
- }
- Console.Read();
- }
- }
运行结果:

我们来改一行代码:
把下面这段:
- public TestListener(TestClassHasEvent inject)
- {
- _inject = inject;
- _inject.YourEvent += new TestClassHasEvent.TestEventHandler(_inject_YourEvent);
- }
改成:
- public TestListener(TestClassHasEvent inject)
- {
- SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
- }
- void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
- {
- }
看看运行结果:

内存泄露了
加个Dispose手动注销事件,然后使用Using关键字,就没有问题了
- class TestListener : IDisposable
- {
- byte[] m_ExtraMemory = new byte[1000000];
- private TestClassHasEvent _inject;
- public TestListener(TestClassHasEvent inject)
- {
- SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
- }
- void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
- {
- }
- #region IDisposable Members
- public void Dispose()
- {
- SystemEvents.DisplaySettingsChanged -= new EventHandler(SystemEvents_DisplaySettingsChanged);
- }
- #endregion
- }
- class Program
- {
- static void DisplayMemory()
- {
- Console.WriteLine("Total memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true));
- }
- static void Main()
- {
- DisplayMemory();
- Console.WriteLine();
- for (int i = 0; i < 5; i++)
- {
- Console.WriteLine("--- New Listener #{0} ---", i + 1);
- using (var listener = new TestListener(new TestClassHasEvent()))
- {
- //do something
- }
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
- DisplayMemory();
- }
- Console.Read();
- }
- }
上面两个例子一个内存泄露,一个没有内存泄露,我想你应该知道原因了,根本区别在于后者有个SystemEvents.DisplaySettingsChanged事件,这个事件是静态Static事件,所以绑定到这个事件上的对象都不会被释放
- // Type: Microsoft.Win32.SystemEvents
- // Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- // Assembly location: C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client\System.dll
- using System;
- using System.ComponentModel;
- namespace Microsoft.Win32
- {
- public sealed class SystemEvents
- {
- public static IntPtr CreateTimer(int interval);
- public static void InvokeOnEventsThread(Delegate method);
- public static void KillTimer(IntPtr timerId);
- public static event EventHandler DisplaySettingsChanging;
- public static event EventHandler DisplaySettingsChanged;
- public static event EventHandler EventsThreadShutdown;
- public static event EventHandler InstalledFontsChanged;
- [EditorBrowsable(EditorBrowsableState.Never)]
- [Obsolete("This event has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")]
- [Browsable(false)]
- public static event EventHandler LowMemory;
- public static event EventHandler PaletteChanged;
- public static event PowerModeChangedEventHandler PowerModeChanged;
- public static event SessionEndedEventHandler SessionEnded;
- public static event SessionEndingEventHandler SessionEnding;
- public static event SessionSwitchEventHandler SessionSwitch;
- public static event EventHandler TimeChanged;
- public static event TimerElapsedEventHandler TimerElapsed;
- public static event UserPreferenceChangedEventHandler UserPreferenceChanged;
- public static event UserPreferenceChangingEventHandler UserPreferenceChanging;
- }
- }
注意Static,注意Singleton
这种static的东西生命周期很长,永远不会被GC回收,一旦被他给引用上了,那就不可能释放了。上面的例子就是
SystemEvents.DisplaySettingsChanged += new
EventHandler(SystemEvents_DisplaySettingsChanged);那就意味着这个类被
SystemEvents.DisplaySettingsChanged
引用了,通过它的函数。另外一个要注意的是Singleton单例模式实现的类,他们也是static的生命周期很长,要注意引用链,你的类是否被它引用
上,如果在它的引用链上,就内存泄露了。
另外还有注意程序运行期间不会释放的对象的事件
还有一种情况,既不是你的对象被static对象而不能释放,也不是Singleton,而是你的对象被一个永远不释放的对象引用着,这个对象或许
不是static的。这种类型很多,比如你的界面有个MainForm,嘿嘿,这个MainForm永远不会关闭和释放的,被它引用了那就不会释放了。看
个例子:
MainForm里面有个public event,MainForm里面打开Form2,然后关闭,看看Form2能不能释放:
- public partial class MainForm : Form
- {
- public event PropertyChangedEventHandler PropertyChanged;
- protected virtual void OnPropertyChanged(string propertyName)
- {
- PropertyChangedEventHandler handler = PropertyChanged;
- if (handler != null)
- handler(this, new PropertyChangedEventArgs(propertyName));
- }
- public MainForm()
- {
- InitializeComponent();
- }
- private void button1_Click(object sender, EventArgs e)
- {
- Form2 frm = new Form2();
- this.PropertyChanged += frm.frm_PropertyChanged;
- //MainForm referenced form2, because main form is not released, therefore form2 will not released.
- DialogResult d = frm.ShowDialog();
- GC.Collect();
- ShowTotalMemory();
- }
- private void ShowTotalMemory()
- {
- this.listBox1.Items.Add(string.Format("Memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true)));
- }
- }
Form2里面有个函数:
- public partial class Form2 : Form
- {
- public Form2()
- {
- InitializeComponent();
- }
- public void frm_PropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- }
- }
所以这种情况下,你的Event handler没有手动注销,那就肯定内存泄露了。
2.静态变量
静态变量中的成员所占的内存不果不手动处理是不会释放内存的,单态模式的对象也是静态的,所以需要特别注意。因为静态对象中的成员所占的内存不会释
放,如果此成员是以个对象,同时此对象中的成员所占的内存也不会释放,以此类推,如果此对象很复杂,而且是静态的就很容易造成内存泄露。
3.非托管资源
因为非托管资源所占的内存不能自动回收,所以使用后必须手动回收,否则程序运行多次很容易造成内存泄露
4.Dispose方法没被调用,或Dispose方法没有处理对象的释放。这样也会造成内存泄露
5.当一个查询语句查询出来的数据量很大,达到几百万条数据时存放到datatable 或dataset中也会造成内存溢出,这是可以采用分页查询等其他方法来解决
net 内存泄露和内存溢出的更多相关文章
- java内存泄露与内存溢出
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory: 内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空 ...
- C++内存机制中内存溢出、内存泄露、内存越界和栈溢出的区别和联系
当我们在用C++做底层驱动的时候,经常会遇到内存不足的警告,究其原因,往往是因为内存出现溢出,泄露或者越界等原因.那么他们之间有什么联系吗? 内存溢出(out of memory) 是指程序在申请内存 ...
- Android为TV端助力 转载:内存泄露与内存溢出的区别
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出. ...
- Android之内存泄露、内存溢出、内存抖动分析
内存 JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆.栈和方法区.栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放.优点:速度快.堆(heap) ...
- java中内存泄露和内存溢出
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出. ...
- Java:内存泄露和内存溢出
1. 内存溢出 (Memory Overflow) 是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那就 ...
- Android 的内存泄露和内存限制
转载自 https://blog.csdn.net/goodlixueyong/article/details/40716779 https://blog.csdn.net/vshuang/artic ...
- 如何避免JavaScript的内存泄露及内存管理技巧
发表于谷歌WebPerf(伦敦WebPerf集团),2014年8月26日. 高效的JavaScript Web应用必须流畅,快速.与用户交互的任何应用程序,都需要考虑如何确保内存有效使用,因为如果 ...
- C++ 内存泄露和内存越界
内存泄露:分配了内存而没有释放,逐渐耗尽内存资源,导致系统崩溃内存越界: 打个比方 就是你有一个500ml的水瓶,然后你倒在瓶里的水大于500ml 那个多余的就会流出来... 1. 原理分析经常有些新 ...
随机推荐
- Android开发系列之AChartEngine
Android图表控件的开发 曾经开发过一个小程序,在Android电视机上面开发一个APP,用于显示一些统计图表的信息.最后找来找去基于Android Native开发有AChartEngine现成 ...
- CSS3 animation-fill-mode 属性
现在专注于移动端开发项目,对于动画这个点是非常重要的,每当我遇到一个新的知识点,我就会和大家一起分享 animation-fill-mode :把物体动画地从一个地方移动到另一个地方,并让它停留在那里 ...
- 51nod动态规划-----矩阵取数
一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值. 例如:3 * 3的方格. 1 3 3 2 1 3 2 2 1 能够获得的最 ...
- 一个页面,多个flash(刚学jq插件)
只贴js那部分哦 调用 // flash轮播图 var sumF=$('.btnTabs span').length/4; //有四个flash var flashT01=new flash($('. ...
- Oracle表空间传输测试
源数据库平台:window 7 64bit Oracle 11g 64bit目标数据库平台:RHEL6 64bit Oracle 11g 64bit 1.查看数据集 select * from nls ...
- linux安装mysql出现Could NOT find Curses (missing CURSES_LIBRARY CURSES_INCLUDE_PATH),提示解决方法
[root@localhost mysql-5.5.11]# cmake . 出现以下错误提示: -- Could NOT find Curses (missing: CURSES_LIBRARY ...
- 数据结构与算法C语言实现笔记(1)--表
声明:此一系列博客为阅读<数据结构与算法分析--C语言描述>(Mark Allen Weiss)笔记,部分内容参考自网络:转载请注明出处. 1.表 表是最简单的数据结构,是形如A1.A2. ...
- 常用后台frame框架
一般后台框架结构: top:左边显示logo,右边显示模块信息. left:对应模块的菜单信息. content:具体的内容. bottom:版权.时间等一些碎屑信息. Html代码: <htm ...
- UML用户指南--UML图简介
本节和大家一起学习一下UML图,这里主要介绍UML结构图和UML行为图两部分,下面让我们一起看一下UML图的详细介绍吧. UML图 这里再次提到对软件体系结构进行可视化.详述.构造和文档化,有5种最重 ...
- css 垂直同步的几种方式
第一种: 利用 display:table 和 display:table-cell 的方式 这种方式就好像将table布局搬过来一样,相信大家对table的td还是有印象的,它的内容是可以设置垂直居 ...