2025年4月10日 星期四

[研究]ASP.NET,System.OutOfMemoryException 的 Memory 指的是甚麼特殊區塊的記憶體?

[研究]ASP.NET,System.OutOfMemoryException 的 Memory 指的是甚麼特殊區塊的記憶體?

2025-04-10

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************


看到 System.OutOfMemoryException 訊息時,「工作管理員」顯示16 GB被用了 9.4 GB,RAM 並沒有真正被用盡,請問 System.OutOfMemoryException 的 Memory 指的是甚麼特殊區塊的記憶體 ?

ChatGPT 說:

這個問題非常好,而且很多開發者初期都會被「工作管理員只用了 9.4 GB / 16 GB,為什麼還報 OutOfMemoryException?」這件事搞混。這其實牽涉到 .NET 運作的記憶體模型,而 System.OutOfMemoryException 所指的並不等於「整台機器的實體記憶體用完了」,而是以下幾種更細緻的原因。

一、OutOfMemoryException 真正的意思

它的實際意義是:.NET 執行環境無法配置所需的記憶體區塊。

也就是說,即使系統還有可用的實體記憶體,只要 .NET runtime 無法找到一個連續的足夠大記憶體區塊,它也會拋出這個例外。

二、造成 OutOfMemoryException 的常見原因(即使 RAM 還沒爆)

1. Large Object Heap (LOH) 碎裂 / 空間不足

  • LOH 會儲存超過 85,000 bytes(約 83 KB) 的物件(例如大陣列、字串、圖像等)。
  • 如果你的應用程式不斷配置/釋放大物件,而又沒有適時 compact,就會造成 記憶體碎裂(fragmentation)。
  • 雖然總 RAM 看起來還很夠,但無法找到「連續的空間」,就會拋出 OutOfMemoryException。

2. 32-bit 應用程式限制(最多使用約 2GB 虛擬記憶體)

  • 如果你的 ASP.NET 應用程式是在 32-bit 模式下執行,不管你有多少 RAM,它最多只能用約 2GB 的虛擬記憶體。
  • 這是最常見的原因之一。
  • 可改設定 IIS 應用程式池為 Enable 32-bit Applications = false 以使用 64-bit 模式。

3. 記憶體分配請求太大

例如:


byte[] buffer = new byte[int.MaxValue];    // 2GB 以上,通常直接炸   

單次分配請求超出上限也會立即引發 OutOfMemoryException,即使整體還有空間。

4. GC 無法回收記憶體

記憶體被「誤保留」或長期持有(例如 static 變數、cache、不正確使用 singleton),導致 GC 難以回收。

三、如何進一步診斷

使用工具觀察:

Visual Studio Diagnostic Tools / dotMemory / PerfView / DebugDiag

註:如果是開發機上就發生 System.OutOfMemoryException,可以這樣;但若開發機上正常,正式機上才發生,要考慮是否合適在正式機安裝偵測工具。

重點觀察:

  • LOH 占用情況
  • 記憶體碎裂情況
  • 哪些型別的物件持續存在、無法被 GC 回收

解法建議(對應原因):

問題類型建議解法
LOH 碎裂減少大物件的反覆配置,可使用 ArrayPool 或重複利用
32-bit 限制改用 64-bit 模式(關掉 IIS 的 Enable 32-bit)
記憶體分配過大拆小 buffer、改用分段讀取、避免一次塞入太多資料
GC 無法回收檢查 static / cache / singleton / event handler 是否未釋放物件

註:關掉 IIS 的 Enable 32-bit 有可能導致某些 3rd Party 套件 or 元件在編譯 or 執行時期 ( Runtime ) 出現錯誤。

(完)

相關

沒有留言:

張貼留言