.Net内存溢出(System.OutOfMemoryException)的常见情况和
处理⽅式总结
在什么情况下会出现OutOfMemonryException呢? 在我们试图新建⼀个对象时,⽽垃圾收集器⼜不到任何可⽤内存时被抛出,这种情况下我们是可以捕获该异常的; 另⼀种情况是,CLR需要内存时,⽽却系统却不能提供,也会抛出该异常. 但此时,我们的应⽤程序是不能捕获该错误的.
内存溢出(OutOfMemoryException)的调试分析
32位操作系统的寻址空间是4G,其中有2G被操作系统占⽤,也就是说留给⽤户进程的内存只有2G(其中还要扣除程序加载时映像占⽤的部分空间,⼀般只有1.6G~1.8G左右可以使⽤)。如果进程运⾏中需要申请内存,⽽操作系统⽆法为其分配内存空间,则会产⽣内存不⾜的异常,在中为System.OutOfMemoryException(The exception that is thrown when there is not enough memory tocontinue the execution of a program.)。虽然最终的表现都为OutOfMemoryException,但其产⽣的原因可能是不⼀样的,动⼿解决此问题之前需要先对进程当前内存的使⽤状态进⾏分析,出正确的原因,才能对症下药。下⾯分享⼀下调试此类问题的⼀些⼼得。
iis应⽤程序池内存溢出错误 System.OutOfMemoryException
在ASP.NET Web服务器上,ASP.NET所能够⽤到的内存,通常不会等同于所有的内存数量。在fig配置⽂件中,配置节
<processModel>中有⼀个属性“memoryLimit”,这个属性的值是⼀个百分值,默认为“60”,即指定了ASP.NET进程(在任务管理器中⼤家就可以看到ASP.NET的进程,IIS5中为aspnet_wp,IIS6中为w3wp)能够使⽤所有物理内存的60%。当ASP.NET使⽤的内存量超过这个限额时,IIS会开始⾃动回收(recycle)进程,即创建⼀个新的进程去负责应付Http请求,⽽将旧进程所占⽤的内存回收。
当我们有⼀台很⼤内存的服务器时,“memoryLimit”这个值是需要进⾏适当的调整的。⽐如我们准备了⼀台chemas-microsoft-com ffice marttags" />t="on">4G内存的服务器,那么t="on">4G×60%=t="on">2.4G。但是,对于Win32操作系统,⼀个进程所能占⽤的所有内存空间只有t="on">2G。当ASP.NET进程占⽤的内存开始达到t="on">2G时,由于它并没有达到t="on">2.4G的“回收阈值”,所以IIS不会启动recycle 进程操作,但是由于Win32的限制,实际上已经不能给这个进程分配更多的内存了,于是,OutOfMemoryException就很可能会被抛出了。为了避免这样的情况,我们就必须将“memoryLimit”适当调⼩,以让IIS更早的进⾏进程回收。
微软推荐的ASP.NET进程占⽤内存是不超过60%,并最好使计算出的实际值不超过t="on">800M。就是说,对于⼀台t="on">4G内存的服务器,最好将“memoryLimit”属性设置成“20”。设置⼀个适当的回
收阈值,让IIS适时的进⾏进程回收,对于保证整个服务器的稳定运⾏,避免OutOfMemoryException是⾮常重要的。aspnet和net的区别
在IIS6中,ASP.NET进程的回收阈值不再由配置节中的“memoryLimit”属性决定,⽽是由IIS管理器中的应⽤程序池配置中的设置决定。
但是,即使正确设置了这些配置,也不能保证完全避免OutOfMemoryException的发⽣,原因可能是多样⽽复杂的,⽐如内存回收操作可能耗时太多等等。开发⼈员要注意的,就是在代码中时刻牢记不要⽆谓的使⽤和浪费内存。:)
如果你有⼀台⼤内存的服务器,同时对Win32操作系统中对于进程最⾼使⽤t="on">2G内存的限制很郁闷,可选的解决⽅法有两个:
1. 使⽤/3GB模式启动计算机,⽅法参加⽂后的链接
2. 使⽤Windows Server 2003 64bits Edition
避免内存溢出的⼏点要素
如果要创建数组,请确保其⼤⼩正确。
确保有⾜够的内存⽤于内部⽤途和新的托管对象。
如果您正在 .NET Compact Framework 上进⾏编程,当没有⾜够的内存可⽤于内部⽤途或新的托管对象时,公共语⾔运⾏库会引发此异常。要避免此异常,应避免编写占⽤ 64KB 或更多内存的⼤⽅法。
过多的托管内存使⽤量通常由以下因素造成:
1. 将⼤型数据集读⼊内存中。
2. 创建过多的缓存条⽬。
3. 上载或下载⼤⽂件。
4. 在分析⽂件时过多地使⽤正则表达式或字符串。
5. 过多的视图状态。
6. 会话状态中有过多的数据或者会话过多。
7. 当对 COM 对象调⽤⼀个⽅法,并且该⽅法返回包含安全数组(⼤⼩不固定的数组)的⽤户定义类型时,可能引发此异常,并附带⼀
条额外的消息“存储空间不⾜,⽆法完成此操作”。这是因为 .NET Framework ⽆法封送带有安全数组类型的结构字段。
⼀种不当使⽤字节数组导致内存溢出的情况举例
1.
public partial class _Default : System.Web.UI.Page
2.
{
3.
protected void Page_Load(object sender, EventArgs e)
4.
{
5.
byte[] bytes = File.ReadAllBytes("D:\toClient.xls");//toClient.xls ⼤⼩为20M
6.
Response.BinaryWrite(bytes);
7.
}
8.
}
上⾯的程序如果所输出的⽂件特别⼤的话,有可能会直接报:System.OutOfMemoryException。正确的做法是把⽂件的字节流分段输出,其实asp有现成的⽅法Response.WriteFile(filePath)就是这么做的。
如下是正确的写法:
1.
Response.ContentType = "application/octet-stream";
2.
Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(downloadName,
System.Text.Encoding.UTF8));
3.
Response.WriteFile("D:\toClient.xls");
4.
Response.Flush();
5.
Response.End();
当asp出现内存溢出时,⼀种简单的处理⽅法是马上回收应⽤程序池。但是这样并没有彻底解决问题。
创建Image类型时出现内存溢出(System.OutOfMemoryException)
错误代码: System.Drawing.Image myimg=System.Drawing.Image.FromFile(file.FullName);
当打开的⽂件不是图像⽂件时会引发的异常:
MSDN:如果⽂件没有有效的图像格式,或者如果 GDI+ 不⽀持⽂件的像素格式,则此⽅法将引发 OutOfMemoryException 异常。
这样的异常信息容易让⼈误解。