.Net中的内存泄露
.Net中的内存泄露
说明:
虽然已经有GC垃圾回收器在工作,但是还是会出现内存泄露。
内存碎片
费托管内存泄露比托管内存泄露更加严重。GC可以移动托管内存,为其他对象腾空间。但是非托管内存将永远的卡在它的位置。
GC的工作原理
GC遍历所有GC Root对象,将其标记为不回收;然后GC转到他们引用的所有对象,并将它们标记为不回收。最后GC回收剩下的所有内容。
GC Root
GCRoot包括:正在运行的线程的实时堆栈;静态变量;通过interop传递到COM对象的托管对象。
起因:
- 对象资源被引用,但是却未被使用!就因为它们被引用了,所以GC不会清理它们,这样它们将永久占用内存。
例如:注册了一个事件+=;但是不注销-=,就会发生这种情况。这被专业的称为:托管内存泄露。
- 当通过某种方式分配非托管内存,就没有GC参与了,因此也不会进行释放。.Net中本身就有很多类会分配非托管内存。几乎所有涉及到流、图形、文件系统或网络调用的操作都会在背后分配非托管内存。这些类通常会提供Dispose()方法来进行内存释放。
- .Net提供如Marshal/PInvoke这些特殊的类来实现非托管内存的分配。
八种内存泄露
八种内存泄露情况,前6种是托管内存泄露,后2种是非托管内存泄露。
订阅Events
.Net中的Events因导致内存泄露而出名。起因:订阅事件后,该事件对象将保留对你相应类的引用。除非使用不捕获类成员的匿名方法。

假设wifiManager的寿命超过MyClass,那么就已经造成了内存泄露。wifiManager会引用MyClass的任何实例,且GC不会回收它们。
解决方法:
- 注销该事件的订阅-=;
- 使用弱句柄weak-handler模式。
- 使用匿名函数进行订阅,且不要捕获任何类成员。
在匿名方法中捕获类成员
虽然事件机制需要引用一个对象,但是引用对象在匿名方法中捕获类成员时却不明显。

上面的匿名方法中捕获了_id,因此该实例也会被引用。只意味着这个匿名方法还会引用MyClass实例。

可以通过定义局部变量,将_id赋值给localId,此时该匿名方法将不会捕获MyClass了,就可以避免潜在的内存泄露。
静态变量
静态变量及其引用的所有内容都不会被GC回收。
缓存功能
无限次的缓存,最终将耗尽内存。
Var
解决方法:
- 删除一段时间未使用的缓存;
- 限制缓存大小;
- 使用弱引用来保存缓存对象。
错误的WPF绑定
WPF 中的绑定实际上可能会导致内存泄露。通常绑定到DP依赖属性上和实现了INotifyPropertyChanged属性上时是安全的。否则WPF会创建从静态变量到绑定源VM VIEWMODEL的强引用,从而导致内存泄露。
也就是说,定义属性时,要实现INotifyPropertyChanged接口,这会通知WPF不要创建强引用。
另一个是绑定到集合Collection时,也会发生内存泄露。所以要绑定的集合必须要实现INotifyCollectionChanged接口。可以使用现成实现了该接口的observableCollection来避免此问题。
永不终止的线程
GC是不会回收实时堆栈的,实时堆栈中包括正在运行的线程中所有的局部变量和调用堆栈的成员。
出于某种因素,需要创建一个永远运行的线程如Timer,这可能会造成内存泄露。
如果你并没有真正的停止这个timer,那么他会在一个独立的线程中运行,并且timer中用到的各种对象实例是不会被GC回收的。
没有回收非托管内存
非托管内存需要手动编码来回收,而不仅仅是避免不必要的引用。

上述方法使用Marshal.AllocHGlobal方法分配了非托管内存缓冲区。
AllocHGlobal会调用Kernel32.dll中的LocalAlloc方法。如果没有手动调用Marshal.FreeHGlobal来回收内存,则该缓冲区内存将被视为占用了进程的内存堆,从而导致内存泄露。
添加了Dispose方法却不调用它
为了避免这种情况发生,可以使用using语句
Using(var instance=new MyClass){…//do what you want}
编译器会将上面的代码转换为:

使用Dispose Pattern

这种模式可确保即使没有调用Dispose,Dispose也将在实例被垃圾回收时被调用。另一方面,如果调用了Dispose,则finalizer将被抑制(SuppressFinalize)。抑制finalizer很重要,因为finalizer开销很大并且会导致性能问题。
然而,dispose-pattern不是万无一失的。如果从未调用Dispose并且由于托管内存泄漏而导致你的类没有被垃圾回收,那么非托管资源也将不会被释放。
.Net中的内存泄露的更多相关文章
- 查找并修复Android中的内存泄露—OutOfMemoryError
[编者按]本文作者为来自南非约翰内斯堡的女程序员 Rebecca Franks,Rebecca 热衷于安卓开发,拥有4年安卓应用开发经验.有点完美主义者,喜爱美食. 本文系国内ITOM管理平台 One ...
- 利用Instrument Leak来发现App中的内存泄露
XCode提供了一组用于检测内存,调试动画,布局等的工具.对于调试一些性能问题,内存问题非常方便.这里我们使用Leak来发现代码中的内存泄露. 在Leak中启动我们的应用开始监控: 注意,在监控的时候 ...
- Android内存优化8 内存检测工具2 LeakCanary——直白的展现Android中的内存泄露
之前碰到的OOM问题,终于很直白的呈现在我的眼前:我尝试了MAT,但是发现不怎么会用.直到今天终于发现了这个新工具: 当我们的App中存在内存泄露时会在通知栏弹出通知: 当点击该通知时,会跳转到具体的 ...
- LeakCanary——直白的展现Android中的内存泄露
之前碰到的OOM问题,终于很直白的呈现在我的眼前:我尝试了MAT,但是发现不怎么会用.直到今天终于发现了这个新工具: 当我们的App中存在内存泄露时会在通知栏弹出通知: 当点击该通知时,会跳转到具体的 ...
- Java中的内存泄露 和 JVM GC(垃圾回收机制)
一.什么是Java中的内存泄露? 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点, 首先,这些对象是可达的,即在有向图中,存在通路可以与其相连:其次,这些对象是无用的,即程序以 ...
- Qt应用中检测内存泄露——VLD
本文简要描述一下在Qt应用中使用VLD来检测内存泄露.本次测试环境:QtCreator2.3 + Qt4.7.4-vs2008 + VS2008 Express. 1.下载并安装:VLD-2.2: h ...
- C++中避免内存泄露常见的解决方式
常见内存泄露及解决方式-选自ood启发录 new/delete, array new/arrray delete匹配 case 1: 在类的构造函数与析构函数中没有匹配地调用 new/delete! ...
- [lua] mac上如何编译snapshot(检测Lua中的内存泄露)
最近我们的unity手游频繁闪退,只要进入战斗场景,之后一段时间就会闪退,如果是在unity编辑器中则会报出not enough memory的错误!猜测应该是有内存泄漏: 由于我们使用了tolua, ...
- Java中的内存泄露的几种可能
Java内存泄漏引起的原因: 内存泄漏是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏. 长生命周期的对象持有短生命周期对象的引用就很可能发 ...
- VS2008中捕获内存泄露(转)
内存泄露十分讨厌,捕获内存泄露更加令人厌烦…… 其实,VS本身就有内存泄露的检测机制.只需做以下操作即可开启.(同时必须在debug模式 下运行程序并且以 正常流程退出 ) // 在入口函数cpp中添 ...
随机推荐
- 一文学会TextureID渲染到Surface
最近遇到一个需求,要求将一个GL_TEXTURE_2D类型的纹理ID写入到ImageReader生成的Surface中. 其实这个需求与我之前写过的一篇文章 一文学会MediaCodeC与OpenGL ...
- 好用的log4j.properties配置文件(按照级别打印日志,每天生成不同类型的日志,可以打印sql日志)
日志按照级别分类 log4j.rootLogger = INFO,stdout,D,E,I #ShuChuDaoDaYingTai log4j.appender.stdout = org.apache ...
- Mysql报错:Specified key was too long; max key length is 767 bytes
1.show variables like 'innodb_large_prefix'; show variables like 'innodb_file_format'; 修改为如下配置: set ...
- 3D相册 复仇者联盟
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Wow: 基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架
领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件溯源 架构图 事件源 可观测性 OpenAPI (Spring WebFlux 集成) 自动注册 命 ...
- IE浏览器不支持TextDecoder()的问题
IE浏览器不支持TextDecoder()方法,因此在进行Arrbuffer转string或中文时,出现未定义的错误.通过网上查找方法,可以通过引用第三方库进行解决. github地址:https:/ ...
- 几种常用到的 Hybrid App 技术框架
移动操作系统在经历了诸神混战之后,BlackBerry OS.Symbian OS.Windows Phone 等早期的移动操作系统逐渐因失去竞争力而退出.目前,市场上主要只剩下安卓和 iOS 两大阵 ...
- 《Kali渗透基础》15. WEB 渗透
@ 目录 1:WEB 技术 1.1:WEB 攻击面 1.2:HTTP 协议基础 1.3:AJAX 1.4:WEB Service 2:扫描工具 2.1:HTTrack 2.2:Nikto 2.3:Sk ...
- JS遍历Json串并获取Key和Value
//data为json串 for (var key in data) { console.log(key); console.log(data[key]); }
- jquery实现表格导出Excel
使用jQuery,jszip.js,FileSaver.js,excel-gen.js插件直接将网页中的table表格导出到本地Excel文件,而不需要经过后台. 导出结果: 实现步骤: 1.进入相关 ...