.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.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...
随机推荐
- linux在命令执行过程中ctrl +z 后[1]+ Stopped
进程挂起 stopped 代表有进程挂起 [1]是id号 可以通过Linux命令:jobs 查看挂起进程 fg 1 把任务1放到前台 bg 1 把任务1放到后台
- HDU 5820 Lights (2016多校7L,主席树)
题意 给定n个平面上的点,坐标范围为[1, 50000].如果对于任意两个点,都可以通过直走(中途经过其他点)走到. 那么输出YES,否则输出NO. 首先排序,去重. 我们要找的点对是只能斜对角走到 ...
- 洛谷——P2299 Mzc和体委的争夺战
P2299 Mzc和体委的争夺战 题目背景 mzc与djn第四弹. 题目描述 mzc家很有钱(开玩笑),他家有n个男家丁(做过前三弹的都知道).但如此之多的男家丁吸引来了我们的体委(矮胖小伙),他要来 ...
- 洛谷——P1416 攻击火星
P1416 攻击火星 题目描述 一群外星人将要攻击火星. 火星的地图是一个n个点的无向图.这伙外星人将按照如下方法入侵,先攻击度为0的点(相当于从图中删除掉它),然后是度为1的点,依此类推直到度为n- ...
- 03、NavMesh--导航网格寻路
一.概述: NavMesh是3D游戏世界中用于实现动态物体自动寻路的一种技术,他将游戏场景中复杂的结构组织关系简化为带有一定信息的网格, 进而在这些网格的基础上通过一些列的计算来实现自动寻路. 二.简 ...
- luogu P1979 华容道
solution 被假hash可了半天....sadQAQ code // luogu-judger-enable-o2 #include<queue> #include<cstdi ...
- 【动态规划】mr351-办签证
[题目大意] xuzhenyi要办个签证.办证处是一座M层的大楼,1<=M<=100. 每层楼都有N个办公室,编号为1..N(1<=N<=500).每个办公室有一个签证员. 签 ...
- ubuntu16安装navicat字体显示不正常,显示方框以及字体倒立
昨天遇到了这个问题,网上找了很多方法都没有真正解决这个问题. 目前其他博客论坛说的主要方法有 1)将安装目录下的./start_navicat中的字符集改为zh_CN.UTF-8 2)将系统的默认字符 ...
- JavaScript之几种创建函数的区别以及优缺点。
工厂模式 function createPerson(name,age,job){ var o = new Object(); o.name = name; o.age = age; o.job = ...
- PHP stream 学习笔记一(同步阻塞 IO 模型)
原文http://blog.csdn.net/shagoo/article/details/6396089 [root@localhost php]# vi server_one.php <?p ...