.NET 之 有效预防.NET应用程序OOM
大部分的内存溢出(及内存泄漏)都和不好的开发习惯有直接关系,以下几个方式可以有效预防OOM。
一、批量和分页
每个合格的coder对数据的处理,必须要有分页或批量多次的意识。大数据量的读取或查询结果集是内存占用大户,是系统性能下降的直接原因之一。
在典型的互联网web应用中,数据量较大且高并发的情况下,不分页,或者不进行批量处理,每次总是取出很多用户数据,很容易造成内存开销过大,系统内存吃紧。再比如我们有时候进行文件操作,读取文件内容的时候就要斟酌考虑文件有多大。
如果你的项目中还在出现不分青红皂白一次查询返回N(N有多大?)条记录的DataSet、DataTable或者列表记录等等情况,或者查询大量数据写入临时表,或者一次读取很大文件内容......。
二、慎用静态
这个也是常见但是比较隐式的引起内存泄露的元凶之一。
静态类、静态字段、静态属性,静态委托,静态方法…静态的好处当然显而易见,比如调用方便,常驻内存提高性能等等,所以,有些代码索性静态到底,除了实体层,在表现层,数据访问层、业务逻辑层、公共组件、配置管理等等,能静态的全给它用上静态。
比起大数据查询造成的常发性的内存不足,使用静态太多的应用程序一时半会也不会内存泄露。可随着系统的运行,静态的东西越来越多,内存开销也就越大,由于GC的回收策略,无效的静态所占内存又不容易及时释放,久而久之就造成了内存不足。
使用静态的情况在分层应用程序中非常常见,而且由于它的好处容易得到体现而隐藏的风险不容易暴露出来,所以很多程序员还是非常执着地使用静态。
三、二方库、三方库,非托管资源,优先使用Dispose模式
有些应用程序需要借助包装的二方库或者三方库,或者使用了非托管资源,如com组件等等,由于.NET自动内存管理和回收,很多人觉得我用一下完成功能就Over了。
实际情况是你调用了别人的库,别人的库也很可能当仁不让地占用了你的内存而你还不自知。
每次调用别人的资源都应该有个警觉性:用你的类库可以,占用我的(内存)不行。
如果你熟悉自动内存管理,熟悉GC,理解Dispose模式,那么一定会在调用别人的资源的时候想着还是using一下为妙,或者,强制赋个null也是举手之劳,要相信某些良好的编程习惯可以让自动内存管理更有效。怕的就是很多人拿来主义,测试不充分,自己调用成功功能完成开发就OK了,交接给别人自己走人。
四、减少字符串临时对象
看到它们有人条件反射似地想到拼接字符串,想到驻留池等等。
没错,不合理地使用String进行操作也会造成内存不足异常,而且这绝不是耸人听闻。
举例来说,对于String的+=,很多应用程序中这个操作层出不穷。我们都知道+=操作会造成很多临时字符串对象,这些对象由于CLR对字符串的驻留处理,容易占用内存空间。如果是高并发的web应用程序,而字符串操作随处可见,且字符串的长度又不确定地长,前端页面各种各样的拼接,久而久之,内存占用就会是一个重大问题。CLR对字符串的优化处理使得字符串不被优先回收,如果字符串操作频繁,临时字符串较长(比如大于等于85000字节)而出现大对象堆的分配,那么更容易出现内存泄露。
很多人可能都会想到如何优化程序去降低string的临时对象的生成概率。对的,StringBuilder的出现就顺理成章了。
五、其他经验
1、Session的不当使用,尤其是使用InProc模式的会话,为了保持状态而选择使用Session,如用户访问量较大将极大消耗服务器资源,而且会出现Session丢失的不稳定现象,所以一般的站点都选择restful的无状态服务;
2、使用较为复杂的数据结构,比如字典里面嵌套字典,字典的键和值也使用字典,曾经碰到过一个非常奇葩的项目,至少5层字典嵌套…有人会反驳说字典是引用类型,而且自动垃圾回收等等等等等等,在OOM面前一切雄辩都苍白无力;
3、过深的继承链,这里尤其要说的是类继承,熟悉垃圾回收的应该都清楚GC回收原理,继承的存在有可能延长类的生命周期而不利于及时回收,所以,如果实际项目中出现继承的深度超过两位数,那一定是抽象出现问题了,重构是必然选择;
4、一些多媒体处理程序的开发中内存泄露情况也非常常见,比如使用GDI+开发画图程序等等,内存消耗严重,这时候托管代码开启dispose模式无比重要;
5、在使用lucene.net的过程中发现有时候创建索引会出现OOM,数据量上去以后,内存不足几乎不可避免,这个时候就必须考虑重新调整架构拆分索引文件分布处理了;
6、有时候调用office组件进行一些报表处理,发现内存好像一下子少了好多?使用7z压缩组件,如果多线程调用,好像也有内存吃紧的现象?
7、调用第三方邮件组件处理邮件和附件,CPU和内存开销都很不能让人满意;
8、不断地注册事件(Event)
六、警惕大对象
以下是一种直达问题本质的内存泄露原因需要分析。
如果你深入理解了内存回收原理以及大对象和大对象堆(Large Object Heap,LOH),那么大对象导致的内存碎片化问题就很好理解了。
简单来说:
1、任何大于等于85000字节的对象都被自动视为大对象,大对象从特殊的大对象堆中分配。大对象堆和小对象堆一样进行终结和释放,但是GC回收算法从来不对大对象堆(Large Object Heap)进行内存压缩整理,因为在堆中下移85000字节或更大的内存块会浪费太多的CPU时间;
2、在.NET中,CLR采用基于代(generation)的垃圾回收,大对象总被认为是第2代(generation)的一部分,GC分析哪些对象不可达,优先分析第0代和第1代,第2代的对象通常被认为长时间存活。
正是由于1和2所述的两个原因(主要原因还是第1个),在垃圾回收过程中容易造成内存碎片。
随着应用程序的运行,如果LOH导致的内存碎片越来越多,内存有效使用率下降会非常严重,比如我们在web应用程序中+=拼接字符串,如果大于等于85000字节的字符串临时对象很多,那么用户量一上去,随着系统的运行,GC回收压力越来越大OOM的风险会变得更高。
虽然内存碎片化导致的OOM看上去似乎无解,但是如果写程序的人仔细分析解决问题,想方设法主动降低创建大对象的频率,那么内存泄露的可能就会降低,足够优秀健壮的程序不能彻底解决OOM,但是我们完全可以将风险发生的情况将至最低可能。
一个足够合格的coder肯定需要具备充足的分析和解决OOM问题的准备和经验,有很多分析和检查OOM的工具如ANTS Memory Profiler,还可以通过调试利器如windbg对内存dump文件进行分析。用好这些工具,让OOM无所遁形也不失为解决之道。
.NET 之 有效预防.NET应用程序OOM的更多相关文章
- Android高效加载大图、多图解决方案,有效避免程序OOM
高效加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库里展示的图片大都是 ...
- Android LruCache 压缩图片 有效避免程序OOM
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9316683 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工, ...
- 每个人都要学的图片压缩终极奥义,有效解决 Android 程序 OOM
# 由来 在我们编写 Android 程序的时候,几乎永远逃避不了图片压缩的难题.除了应用图标之外,我们所要显示的图片基本上只有两个来源: 来自网络下载 本地相册中加载 不管是网上下载下来的也好,还是 ...
- Android高效加载大图、多图解决方案,有效避免程序OOM(转)
本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/training/displaying ...
- 一次容器化springboot程序OOM问题探险
背景 运维人员反馈一个容器化的java程序每跑一段时间就会出现OOM问题,重启后,间隔大概两天后复现. 问题调查 一查日志 由于是容器化部署的程序,登上主机后使用docker logs Contain ...
- Java应用程序OOM分析
内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用. 内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢 ...
- Android高效加载大图,多图解决方案,有效避免程序OOM异常
收藏自:http://blog.csdn.net/guolin_blog/article/details/9316683 谷歌官方文档:http://developer.android.com/tra ...
- 垃圾回收机制GC知识再总结兼谈如何用好GC
一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...
- GC机制总结
一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...
随机推荐
- 关于phonegap的白名单机制
今天在项目中发现了一个问题,使用phonegap开发的APP默认情况下可以将外部网页加载进入手机APP当中,这是相当危险的,同时也会给人一种APP非native的感觉. 可能遇见的一种情况是有些WiF ...
- 【BZOJ 1998】 1998: [Hnoi2010]Fsk物品调度(双向链表+并查集+置换)
1998: [Hnoi2010]Fsk物品调度 Description 现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位.流水线上有n个位置,从0到n-1依次编号 ...
- 【LA 3641】 Leonardo's Notebook (置换群)
[题意] 给出26个大写字母组成 字符串B问是否存在一个置换A使得A^2 = B [分析] 置换前面已经说了,做了这题之后有了更深的了解. 再说说置换群. 首先是群. 置换群的元素是置换,运算时是 ...
- 【UOJ #279】【UTR #2】题目交流通道
http://uoj.ac/problem/279 先判断答案为0的情况,\(d(i,i)\neq 0\),\(d(i,j)\neq d(j,i)\),\(d(i,j)>d(i,k)+d(k,j ...
- [BZOJ5251][九省联考2018]劈配(网络流)
5251: [2018多省省队联测]劈配 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 33 Solved: 22[Submit][Status][ ...
- [BZOJ4815][CQOI2017]小Q的表格(莫比乌斯反演)
4815: [Cqoi2017]小Q的表格 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 832 Solved: 342[Submit][Statu ...
- 【找规律】【DFS】Gym - 101174H - Pascal's Hyper-Pyramids
二维下,如果把杨辉三角按照题目里要求的那样摆放,容易发现,第i行第j列的数(从0开始标号)是C(i+j,i)*C(j,j). 高维下也有类似规律,比如三维下,最后一层的数其实是C(i+j+k,i)*C ...
- 【树链剖分】bzoj2243 [SDOI2011]染色
树链剖分模板题.线段树维护每个段中的颜色数.左端点颜色.右端点颜色. pushup: col[rt]=col[rt<<1]+col[rt<<1|1]-(Rcol[rt<& ...
- Problem A: 深入浅出学算法022-汉诺塔问题II
#include<stdio.h> void hanio(int n,char a,char b,char c) { ) printf("%c->%c\n",a, ...
- lnmp配置信息 4核8g优化
MYSQL my.conf# The following options will be passed to all MySQL clients[client]#password = ...