.Net 内存溢出(System.OutOfMemoryException)的常见情况和处理方式总结



在什么情况下会出现OutOfMemonryException呢? 在我们试图新建一个对象时,而垃圾收集器又找不到任何可用内存时被抛出,这种情况下我们是可以捕获该异常的; 另一种情况是,CLR需要内存时,而却系统却不能提供,也会抛出该异常. 但此时,我们的应用程序是不能捕获该错误的.

内存溢出(OutOfMemoryException)的调试分析

32位操作系统的寻址空间是4G,其中有2G被操作系统占用,也就是说留给用户进程的内存只有2G(其中还要扣除程序加载时映像占用的部分空间,一般只有1.6G~1.8G左右可以使用)。 如果进程运行中需要申请内存,而操作系统无法为其分配内存空间,则会产生内存不足的异常,在.net中为System.OutOfMemoryException(The exception that is thrown when there is not enough memory tocontinue the execution of a program.)。 虽然最终的表现都为OutOfMemoryException,但其产生的原因可能是不一样的,动手解决此问题之前需要先对进程当前内存的使用状态进行分析,找出正确的原因,才能对症下药。下面分享一下调试此类问题的一些心得。

更多内容请参考:http://blog.csdn.net/lazyleland/article/details/6704661

iis应用程序池 内存溢出错误 System.OutOfMemoryException

在ASP.NET Web服务器上,ASP.NET所能够用到的内存,通常不会等同于所有的内存数量。在machine.config配置文件中,配置节中有一个属性“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是非常重要的。

在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 无法封送带有安全数组类型的结构字段。

一种不当使用字节数组导致内存溢出的情况举例

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        byte[] bytes = File.ReadAllBytes("D:\toClient.xls");//toClient.xls 大小为20M
        Response.BinaryWrite(bytes);
    }
}

上面的程序如果所输出的文件特别大的话,有可能会直接报:System.OutOfMemoryException。正确的做法是把文件的字节流分段输出,其实asp.net有现成的方法Response.WriteFile(filePath)就是这么做的。

如下是正确的写法:

Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(downloadName, System.Text.Encoding.UTF8));
Response.WriteFile("D:\toClient.xls");
Response.Flush();
Response.End();

当asp.net出现内存溢出时,一种简单的处理方法是马上回收应用程序池。但是这样并没有彻底解决问题。

创建Image类型时出现内存溢出(System.OutOfMemoryException)

错误代码: System.Drawing.Image myimg=System.Drawing.Image.FromFile(file.FullName);

当打开的文件不是图像文件时会引发的异常:

MSDN:如果文件没有有效的图像格式,或者如果 GDI+ 不支持文件的像素格式,则此方法将引发 OutOfMemoryException 异常。

这样的异常信息容易让人误解。



元素

在 Internet 信息服务 (IIS) Web 服务器上配置 ASP.NET 进程模型设置。只能在 Machine.config 文件中设置 <processModel> 节,并且该节影响服务器上运行的所有 ASP.NET 应用程序。

警告 警告 有关此元素的信息,请阅读“注释”部分。

配置结构的示例:


   web>
      

"true|false"
              timeout="hrs:mins:secs|Infinite" 
              idleTimeout="hrs:mins:secs|Infinite"
              shutdownTimeout="hrs:mins:secs|Infinite"
              requestLimit="hrs:mins:secs|Infinite"
              requestQueueLimit="num|Infinite"
              restartQueueLimit="num|Infinite"
              memoryLimit="percent"
              cpuMask="num"
              webGarden="true|false"
              userName="username"
              password="password"
              logLevel="All|None|Errors"
              clientConnectedCheck="hrs:mins:secs|Infinite"
              responseDeadlockInterval="hrs:mins:secs|Infinite"
              responseRestartDeadlockInterval="hrs:mins:secs|Infinite"
              comAuthenticationLevel="Default|None|Connect|Call| 
                                      Pkt|PktIntegrity|PktPrivacy"
              comImpersonationLevel="Default|Anonymous|Identify|
                                     Impersonate|Delegate"
              maxWorkerThreads="num"
              maxIoThreads="num"/>

可选的属性

属性 选项 描述

clientConnectedCheck     指定在 ASP.NET 检查连接的客户端之前,请求在队列中存在多长时间。
comAuthenticationLevel     为 DCOM 安全指定身份验证级别。默认值为 Connect
    Default 指定 DCOM 使用其正常的安全协商算法来确定身份验证级别。
    None 指定不进行身份验证。
    Connect 指定仅当客户端建立与服务器的关系时,DCOM 才对客户端凭据进行验证。
    Call 指定在每个远程过程调用开始时服务器收到请求的时候,DCOM 对客户端凭据进行验证。
    Pkt 指定 DCOM 验证收到的所有数据是否均来自预期的客户端。数据报传输始终使用 Pkt 身份验证。
    PktIntegrity 指定 DCOM 验证在客户端和服务器之间传输的数据是否未被修改。
    PktPrivacy 指定 DCOM 验证所有先前的级别并加密每个远程过程调用的参数值。
comImpersonationLevel     指定 COM 安全的身份验证级别。
    Default 指定 DCOM 使用其正常的安全协商算法来确定模拟级别。
    Anonymous 指定客户端对服务器是匿名的。服务器可以模拟客户端,但模拟令牌不包含任何信息。在版本 1.1 中不支持 Anonymous
    Identify 指定服务器可以获取客户端的标识。服务器可以模拟客户端以进行访问控制列表 (ACL) 检查,但它不能作为客户端访问系统对象。
    Impersonate 指定服务器进程在代表客户端操作时可以模拟客户端的安全上下文。可以使用此级别的模拟来访问本地资源,如文件。在此级别进行模拟时,只能在一个计算机边界传递模拟令牌。
    Delegate 指定服务器进程在代表客户端操作时可以模拟客户端的安全上下文。在使用掩饰代表客户端操作时,服务器进程也可以对外调用其他的服务器。在其他计算机上,服务器可以作为客户使用客户端的安全上下文访问本地和远程资源。在此级别进行模拟时,可以在任意数量的计算机边界传递模拟令牌。
cpuMask     指定多处理器服务器上的哪些处理器可以运行 ASP.NET 进程。cpuMask 值指定一种位模式,它指示 CPU 可以运行 ASP.NET 线程。例如,cpuMask 十六进制值 0x0d 表示位模式 1101。在具有 4 个 CPU 的计算机上,它指示可以将 ASP.NET 进程安排在 CPU 0、2 和 3,但不能安排在 CPU 1 上。ASP.NET 为每个合格的 CPU 启动一个工作进程。如果将 webGarden 属性(参见下面)设置为 true,则 cpuMask 将工作进程限制为合格 CPU 的数量。(工作进程的最大允许数量等于 CPU 的数量。)默认情况下,启用所有的 CPU,并且 ASP.NET 为每个 CPU 启动一个进程。如果将 webGarden 设置为 false,则忽略 cpuMask 属性,并且只运行一个工作进程。
enable     指定是否启用进程模型。
    true 指示进程模型已启用。
    false 指示进程模型未启用。
idleTimeout     指定在 ASP.NET 自动结束工作进程之前,工作进程处于不活动状态的时间(采用时:分:秒字符串格式)。默认设置为 Infinite
logLevel     指定要记录到事件日志中的事件类型。
    All 指定记录所有的进程事件。
    None 指定不记录任何事件。
    Errors 指定只记录意外关闭、内存限制关闭和死锁关闭。Errors 为默认值。
maxWorkerThreads 5 - 100 配置每个 CPU 上的进程使用的工作线程的最大数量。例如,如果在单处理器服务器上该值为 25,则 ASP.NET 使用运行时 API 将进程限制设置为 25 个。在双处理器服务器上,将该限制设置为 50。默认值为 20。maxWorkerThreads 的值必须大于或等于 配置节中的 minFreeThread 属性设置。
maxIoThreads 5 - 100 配置每个 CPU 上的进程使用的 I/O 线程的最大数量。例如,如果在单处理器服务器上该值为 25,则 ASP.NET 使用运行时 API 将进程限制设置为 25 个。在双处理器服务器上,将该限制设置为 50。默认值为 20。maxIoThreads 的值必须大于或等于 配置节中的 minFreeThread 属性设置。
memoryLimit     指定在 ASP.NET 启动新的进程和重新分配现有请求之前,允许工作进程占用的最大内存大小(总系统内存的百分比)。默认值是 60%。
password     如果给出(与 userName 结合使用),则此属性导致工作进程以配置的 Windows 标识运行。默认值为 AutoGenerate。有关特殊名称 SystemMachine(它们不需要密码)的详细信息以及在注册表中存储加密工作进程凭据的信息,请参阅 userName
pingFrequency     使用标准进程模型格式(时:分:秒)指定时间间隔,ISAPI 扩展按此间隔 ping 工作进程以查看它是否正在运行。如果工作进程在 pingTimeout 间隔内没有运行,则重新启动该工作进程。默认值为 30 秒钟。
pingTimeout     使用标准进程模型格式(时:分:秒)指定重新启动未响应工作进程之前的时间间隔。ISAPI 扩展每隔 pingFrequency 时间间隔 ping 一次工作进程。如果工作进程在 pingTimeout 间隔内没有响应,则重新启动该进程。默认值为 5 秒钟。
requestLimit     指定在 ASP.NET 自动启动新工作进程以替换当前进程之前允许的请求数。默认设置为 Infinite
requestQueueLimit     指定在 ASP.NET 开始给新请求返回“503 - 服务器太忙”错误之前队列中允许的请求数。默认值是 5000。
responseDeadlockInterval     使用标准进程模型格式(时:分:秒)指定重新启动工作进程之前的时间间隔(如果满足以下条件):
  • 具有排队的请求。
  • 在此间隔内没有响应。

默认值为 3 分钟。

responseRestartDeadlockInterval     ASP.NET 不再使用此属性,并且仅出于向后兼容性的需要提供此属性。如果它已在配置文件中存在,则它不会引起配置错误。现在,出现死锁情况下的所有回收是由 responseDeadlockInterval 属性控制的。
serverErrorMessageFile     如果给出,则它指定要使用的文件内容,而不是出现致命错误时给出的默认“服务器不可用”消息。文件位置是与 Machine.config 相对的,也可以是绝对文件路径。如果没有给出该属性,则使用默认的“服务器不可用”消息。
shutdownTimeout     指定工作进程自行关闭前允许的分钟数。当超时到期时,ASP.NET 就会关闭工作进程。时间用时:分:秒字符串格式表示。默认值为 5 秒钟或 0:00:05。
timeout     指定在 ASP.NET 启动新工作进程以替换当前进程之前的时间(以分钟为单位)。默认设置为 Infinite
userName     如果给出,则 userName 属性使用不同于默认进程标识的 Windows 标识运行 ASP.NET 工作进程。默认情况下,将 userName 设置为特殊值 Machine,并且进程运行使用的用户帐户为 ASPNET(在安装 ASP.NET 时自动创建的)。ASPNET 帐户的密码是在安装时以加密形式生成的。如果在 userNamepassword 属性中给出了有效的凭据,则进程使用给定的帐户运行。userName 的另外一个特殊值为 System,密码为 AutoGenerate(它使用管理员帐户来运行进程,并且允许在此进程下运行的所有 ASP.NET 用户代码具有完全管理权限)。有关在用作域控制器的服务器上使用 ASP.NET 的信息,请参阅下面的“注释”部分。

userNamepassword 以明文形式存储在配置文件中。尽管 IIS 将不会为响应用户代理请求而传输 .config 文件,但是可通过其他方法读取配置文件,例如,通过对包含该服务器的域具有正确凭据的经过身份验证的用户访问。为了维护安全性,processModel 节支持在注册表中存储加密的 userNamepassword 属性。凭据必须采用由 Windows 2000 和 Windows XP 数据保护 API (DPAPI) 加密功能加密的 REG_BINARY 格式。详细信息,请参阅下面的“注释”和“示例”部分。

webGarden     在与 cpuMask 属性结合使用时控制 CPU 关系。(多处理器 Web 服务器称为“Web 园”。)
    true 指示 cpuMask 属性用于指定哪些 CPU 适合运行 ASP.NET 进程。
    false 指示 CPU 的使用是由 Windows 操作系统调度的。忽略 cpuMask 属性并且只运行一个工作进程。默认值是 false

注释

托管代码配置系统并不读取 配置设置。而是由非托管 DLL aspnet_isapi.dll 直接读取。重新启动 IIS 后,本节的更改才会生效。

如果在域控制器上安装 ASP.NET,必须采取特殊的步骤,否则安装无法正常进行。详细信息,请参阅位于 http://support.microsoft.com 的 Microsoft 知识库中的文章 CHS315158“ASP.NET 在域控制器上不能使用默认 ASPNET 帐户”。

当 ASP.NET 在 IIS 版本 6 本机模式下运行时,使用 IIS 6 进程模型并且忽略 节中的设置。要配置进程标识、回收或其他进程模型值,请使用 Internet 服务管理器用户界面为应用程序配置 IIS 工作进程。

时间值的格式为“时:分:秒”。如果只给出单个数字而没有冒号,则假定该值为分钟数;因此 timeout="4" 等同于 timeout="00:04:00"。

如果 ASP.NET 应用程序导致 ASP.NET 工作进程(Windows 2000 和 Windows XP Professional 上的 Aspnet_wp.exe 以及 Windows Server 2003 上的 W3wp.exe)重新启动,并给出一条错误消息,指示重新启动是由于怀疑的死锁状态造成的,则应该增加 responseDeadlockInterval 设置。

在注册表中存储用户名和密码

将用户名和密码存储在注册表中

要加密用户名和密码并将它们存储在注册表中,请按如下方式设置 userNamepassword

userName="registry:HKLM\Software\AspNetProcess,Name"

password="registry:HKLM\Software\AspNetProcess,Pwd"

关键字 registry 后面、逗号前面的字符串部分表示 ASP.NET 所打开的注册表项的名称。逗号后面的部分包含一个字符串值名,ASP.NET 将从中读取凭据。逗号是必需的,凭据必须存储在 HKLM 配置单元中。如果配置格式有误,则 ASP.NET 将不启动工作进程,并随后出现当前帐户创建失败代码的路径。

凭据必须采用 REG_BINARY 格式,其中包含对 Windows API 函数 CryptProtectData 调用的输出结果。您可以用 ASP.NET设置注册表控制台应用程序 (Aspnet_setreg.exe) 创建加密凭据并将其存储在注册表中,该应用程序使用 CryptProtectData 完成加密。要下载 Aspnet_setreg.exe 以及 Visual C++ 源代码和帮助,请访问网站 www.asp.net 并搜索“aspnet_setreg”。

您应该对存储加密凭据的注册表项配置访问权限,以便只对 Administrators 和 SYSTEM 提供访问。因为该注册表项将由作为 SYSTEM 运行的 ASP.NET 进程读取,您应该设置下列权限:

Administrators:F

SYSTEM:F

CREATOR OWNER:F

ProcessAccount:R

这将提供两道防线来保护数据:

  • ACL 权限要求访问数据的标识为 Administrator。
  • 攻击者必须在服务器上运行代码 (CryptUnprotectData) 以便恢复帐户的凭据。

示例

以下示例指定几个 <processModel> 配置设置。


   web>
       
         enable="true"
         timeout="15" 
         idleTimeout="25"
         shutdownTimeout="5"
         requestLimit="1000"
         requestQueueLimit="500"
         responseDeadlockInterval="00:03:00"              
         responseRestartDeadlockInterval="Infinite"
         memoryLimit="20"
         webGarden="true"
         maxWorkerThreads="25"
         maxIoThreads="25"/>
   web>

以下示例指定将加密的用户名和密码存储在注册表用户定义的项 AspNetProcess 下面。


   web>
       
         userName="registry:HKLM\Software\AspNetProcess,Name"
         password="registry:HKLM\Software\AspNetProcess,Pwd"
      
   web>

要求

  • 包含在:web> 中
  • Web 平台:IIS 5.0、IIS 5.1、IIS 6.0
  • 配置文件:Machine.config、Web.config
  • 配置节处理程序:System.Web.Configuration.ProcessModelConfigurationHandler

http://doc.51windows.net/iismmc/?url=/iismmc/htm/aaconprocessmodelelement.htm

你可能感兴趣的:(c#,基础)