"# CEF/Chromium 記憶體使用量在長期應用中的使用"
IronPDF使用Chromium進行渲染,因此即使在文件被處理和GC.Collect()運行後,處理記憶體在生成PDF後仍可能在短時間內保持高位。 "這裡有兩個來源發揮作用:Chromium 的非管理本地分配器和 IronPDF 的瀏覽器選項卡池化。" "在大多數情況下,這是預期的,並不會自動意味著存在記憶體洩漏。"
這適用於IronPDF和Windows及Linux上的IronPdfEngine,跨Docker、Kubernetes、VM和伺服器託管環境,以及使用基於Chromium渲染的所有.NET、Java和應用程式。
"## 為什麼記憶體保持升高"
"完成渲染後,有兩個不同的機制會保持記憶體。"
"Chromium 本地分配器保留: Chromium 使用大量的非受管理記憶體,存在於 .NET 垃圾收集器之外。" "渲染完成時,Chromium 通常保留這些本地記憶體以供重用,而不是立即將其返還給操作系統。" 因此您的PdfDocument物件可以正確處理,運行時可以收集托管物件,而整個進程或容器的記憶體仍然可以讀取到高位。 "這是基於 Chromium 的引擎的正常行為。"
"瀏覽器池選項卡重用: IronPDF 可以在一個渲染後保持空閒的瀏覽器選項卡激活,因此下一個開始更快。" "這些選項卡短時間內保留其渲染子進程和 DOM 狀態,即使沒有進行渲染,也會造成明顯的記憶體基線。" "開啟池功能後,您通常會看到計算器在渲染時增長,完成後保持在基線,然後在空閒選項卡超時並清除時逐步下降。"
為什麼GC.Collect()沒有幫助
GC.Collect() 只回收管理的.NET記憶體。 "它不會強制 Chromium 將本地記憶體交還給操作系統,且不會拆除特意保留用於重用的溫 BrowserPool 選項卡。" "即使正確處理和強制收集,任務管理器,Docker,Kubernetes 或工具如 New Relic 顯示的數值也不會立即下降。"
"效果在長期運行的應用程式,共享服務環境以及 Docker 或 Kubernetes 部署中最為明顯。" 對於使用IronPdfEngine的Java整合,壓力通常顯示在引擎過程或容器中,而不是JVM堆中。
"## BrowserPool 預設"
"IronPDF 在渲染之間保持少量選項卡溫,從而提高性能。" "預設值為:"
BrowserPool.Enabled = trueBrowserPool.MaxIdleTabs = min(max(ProcessorCount / 2, 1), 4)BrowserPool.IdleTimeoutSeconds = 30
"因此,即使沒有積極的渲染過程,該過程也可能暫時保持 1 到 4 個空閒選項卡,每個選項卡保留本地記憶體和子進程資源,直到空閒超時過期。" "根據渲染的內容和環境,空閒選項卡可以保留一個明顯的數量,在某些負載下大約為 50 到 100 MB。" "最後一個渲染後,大約 30 秒時間過去後,這種高基線可能會開始逐步下降。"
解決方案
"如果環境受記憶限制,首先要調整的是 BrowserPool 設置。" "預設值如下所示:"
renderer.RenderingOptions.BrowserPool.Enabled = true; // default
renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 2; // default is CPU/2, clamped to 1-4
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 30; // default
renderer.RenderingOptions.BrowserPool.Enabled = true; // default
renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 2; // default is CPU/2, clamped to 1-4
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 30; // default
"### 選項 1:完全禁用選項卡池"
"如果希望在每次渲染後實現最確定性的清理,請選擇此選項。"
renderer.RenderingOptions.BrowserPool.Enabled = false;
renderer.RenderingOptions.BrowserPool.Enabled = false;
renderer.RenderingOptions.BrowserPool.Enabled = False
"### 選項 2:在不保留空閒選項卡的情況下保留 BrowserPool 啟用"
"保持功能啟用,但避免在渲染之間保持溫選項卡,從而實現確定的每次渲染清理。"
renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 0;
renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 0;
"### 選項 3:縮短空閒超時"
"中間立場:保持一些重用優勢,但讓記憶在突發流量後更早下降。"
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10;
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10;
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10
"如何選擇:"
Enabled = false: 記憶體穩定性比快速啟動性能更重要。MaxIdleTabs = 0: 您希望有確定的每次渲染清理,而不完全禁用該功能。- 降低
IdleTimeoutSeconds: 您的工作負載以突發方式到來,您希望在每次突發後更快地回收記憶體。
"## 長期運行應用的策略"
"如果您的應用必須持續保持記憶體低,請按順序執行以下操作,先從 BrowserPool 調整開始,然後在需要時轉向過程回收。"
"### 1. 限制並行渲染"
"幾個 Chromium 渲染作業同時運行會導致本地記憶體壓力急劇增加。" "如果並行渲染,請通過信號量限制同時運行的作業數:"
private static readonly SemaphoreSlim RenderSemaphore = new(2);
public async Task<t> RunRenderAsync<t>(Func<t> renderWork)
{
await RenderSemaphore.WaitAsync();
try
{
return renderWork();
}
finally
{
RenderSemaphore.Release();
}
}
private static readonly SemaphoreSlim RenderSemaphore = new(2);
public async Task<t> RunRenderAsync<t>(Func<t> renderWork)
{
await RenderSemaphore.WaitAsync();
try
{
return renderWork();
}
finally
{
RenderSemaphore.Release();
}
}
Imports System.Threading
Private Shared ReadOnly RenderSemaphore As New SemaphoreSlim(2)
Public Async Function RunRenderAsync(Of T)(renderWork As Func(Of T)) As Task(Of T)
Await RenderSemaphore.WaitAsync()
Try
Return renderWork()
Finally
RenderSemaphore.Release()
End Try
End Function
"將您的 IronPDF 渲染調用包裹在限速部分內,以便一次只運行固定數量的作業。"
"### 2. 調整或禁用 BrowserPool"
對於許多記憶體敏感的部署,這是最有效的第一步。完全禁用BrowserPool,設置IdleTimeoutSeconds以應對突發工作負載。 "這些中的任何一項都可以縮小持續的後渲染基線,而不需完全重啟策略。"
"### 3. 在獨立工作者中隔離渲染"
"在生產系統中將 PDF 渲染移出主應用是強大的一步。" "主應用保持穩定,渲染工作者可以自行重新啟動,當該工作者退出時,本地 Chromium 記憶充分釋放。" 在依賴於回收之前,請確認禁用BrowserPool或設置MaxIdleTabs = 0是否已經能為您提供可預測的每次渲染清理。在Docker或Kubernetes環境中、背景作業系統以及需要更嚴格記憶體隔離的API平台中,隔離方法是最有效的。
"### 4. 需要時僅回收工作者"
"在有硬記憶上限且 BrowserPool 調整仍不足時,在設計數量的作業後回收渲染過程或工作者容器。" "這可能意味著在固定批處理大小後重新啟動專用工作者,旋轉 Kubernetes 中的引擎容器,或將渲染隔離到可以獨立重啟的服務中。" "稍後步驟,不是您的首選。"
"## 可能是記憶體洩漏的時候"
"渲染後記憶保持升高並不一定意味著洩漏。" "基於 Chromium 的渲染有兩種型別的重用需要了解:分配器層次重用,指的是 Chromium 內部保留本地記憶體頁(正常的,無法直接控制),以及 選項卡層次重用,指的是 BrowserPool 在渲染之間保持完整選項卡活躍(可配置的,且通常是您在監控工具中看到的最大貢獻者)。"
"當記憶在渲染時上升,穩定而不是無限增長,之後短時間保持升高,然後在空閒選項卡超時時下降或為下一次渲染保持可用時,這通常是預期的模式。"
"進一步調查時:"
"- 記憶在相似的工作負載下保持上升而不穩定下來" "- 即使減少並發,也保持增長"
- 即使在禁用BrowserPool或設置
MaxIdleTabs = 0後,記憶體仍然持續增長 "- 已通過最少重現展示出相同的模式且受控輸入的情況中"
"## 何時聯繫支援"
"如果您能夠重現以下全部情況,請聯繫 技術支援:"
"1. 記憶在控制的工作負載下抵達穩定而不是持續增長" "2. 限制并發后問題依然存在"
- 在禁用BrowserPool或設置
MaxIdleTabs = 0後,問題仍然存在 "4. 您能夠使用最小的範本專案重現它"
"開票時,請包括您的 IronPDF 版本,OS 和託管環境,Docker 或 Kubernetes 詳細資訊(如適用),程式語言,渲染頻率和并發級別,記憶圖或監控截圖,以及最小可重現的專案。"

