[研究]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 ) 出現錯誤。
(完)
相關
沒有留言:
張貼留言