1. 程式人生 > >.Net 記憶體溢位(System.OutOfMemoryException)的常見情況和處理方式總結

.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配置檔案中,配置節<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是非常重要的。

在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 無法封送帶有安全陣列型別的結構欄位。

一種不當使用位元組陣列導致記憶體溢位的情況舉例

publicpartialclass_Default:System.Web.UI.Page{protectedvoidPage_Load(object sender,EventArgs e){byte[] bytes =File.ReadAllBytes("D:\toClient.xls");//toClient.xls 大小為20MResponse.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 異常。

這樣的異常資訊容易讓人誤解。

<processModel> 元素

在 Internet 資訊服務 (IIS) Web 伺服器上配置 ASP.NET 程序模型設定。只能在 Machine.config 檔案中設定 <processModel> 節,並且該節影響伺服器上執行的所有 ASP.NET 應用程式。

警告 警告 有關此元素的資訊,請閱讀“註釋”部分。

配置結構的示例:

<processModel enable="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 為預設值。
maxWorkerThreads5 - 100配置每個 CPU 上的程序使用的工作執行緒的最大數量。例如,如果在單處理器伺服器上該值為 25,則 ASP.NET 使用執行時 API 將程序限制設定為 25 個。在雙處理器伺服器上,將該限制設定為 50。預設值為 20。maxWorkerThreads 的值必須大於或等於 <httpRuntime> 配置節中的 minFreeThread 屬性設定。
maxIoThreads5 - 100配置每個 CPU 上的程序使用的 I/O 執行緒的最大數量。例如,如果在單處理器伺服器上該值為 25,則 ASP.NET 使用執行時 API 將程序限制設定為 25 個。在雙處理器伺服器上,將該限制設定為 50。預設值為 20。maxIoThreads 的值必須大於或等於 <httpRuntime> 配置節中的 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 分鐘。

responseRestartDeadlockIntervalASP.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

註釋

託管程式碼配置系統並不讀取 <processModel> 配置設定。而是由非託管 DLL aspnet_isapi.dll 直接讀取。重新啟動 IIS 後,本節的更改才會生效。

如果在域控制器上安裝 ASP.NET,必須採取特殊的步驟,否則安裝無法正常進行。詳細資訊,請參閱位於 http://support.microsoft.com 的 Microsoft 知識庫中的文章 CHS315158“ASP.NET 在域控制器上不能使用預設 ASPNET 帳戶”。

當 ASP.NET 在 IIS 版本 6 本機模式下執行時,使用 IIS 6 程序模型並且忽略 <processModel> 節中的設定。要配置程序標識、回收或其他程序模型值,請使用 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> 配置設定。

<configuration>
   <system.web>
      <processModel
         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"/>
   </system.web>
</configuration>

以下示例指定將加密的使用者名稱和密碼儲存在登錄檔使用者定義的項 AspNetProcess 下面。

<configuration>
   <system.web>
      <processModel>
         userName="registry:HKLM\Software\AspNetProcess,Name"
         password="registry:HKLM\Software\AspNetProcess,Pwd"
      </processModel>
   </system.web>
</configuration>

要求

  • Web 平臺:IIS 5.0、IIS 5.1、IIS 6.0
  • 配置檔案:Machine.config、Web.config
  • 配置節處理程式:System.Web.Configuration.ProcessModelConfigurationHandler