Speichernutzung von CEF/Chromium in langlaufenden Anwendungen

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronPDF rendert mit Chromium, daher kann der Arbeitsspeicher kurzfristig hoch bleiben, selbst wenn Dokumente verworfen werden und GC.Collect() läuft. Zwei Quellen sind im Spiel: Chromiums nicht verwalteter nativer Allokator und IronPDFs Browser-Tab-Pooling. In den meisten Fällen wird dies erwartet und bedeutet nicht automatisch, dass ein Speicherleck vorhanden ist.

Dies gilt für IronPDF und IronPdfEngine unter Windows und Linux, ob in Docker, Kubernetes, VM oder servergehosteten Umgebungen, sowie für .NET, Java und jede Anwendung, die Chromium-basiertes Rendering verwendet.

Warum bleibt der Speicher hoch

Zwei unterschiedliche Mechanismen halten den Speicher hoch, nachdem ein Render abgeschlossen ist.

Chromium-nativer Allokator-Retention: Chromium verwendet eine große Menge an nicht verwaltetem Speicher, der außerhalb des .NET Garbage Collectors liegt. Wenn ein Render abgeschlossen ist, behält Chromium oft diesen nativen Speicher zur Wiederverwendung, anstatt ihn sofort an das Betriebssystem zurückzugeben. Damit Ihre PdfDocument Objekte korrekt verworfen werden können, damit die Laufzeit verwaltete Objekte sammeln kann, und der Gesamtprozess oder Container-Arbeitsspeicher kann dennoch hochbleiben. Dies ist normal für Chromium-basierte Engines.

BrowserPool-Tab-Wiederverwendung: IronPDF kann inaktive Browser-Tabs nach einem Render erhalten, sodass der nächste schneller startet. Diese Tabs halten ihre Renderer-Unterprozesse und den DOM-Zustand für kurze Zeit aufrecht und erstellen eine sichtbare Speicherbasislinie, auch wenn nichts gerendert wird. Mit aktivem Pooling sehen Sie in der Regel, dass der Speicher während des Renderings ansteigt, nach Abschluss bei einer Basislinie bleibt und dann in Schritten abnimmt, wenn inaktive Tabs auslaufen und abgeerntet werden.

Warum GC.Collect() nicht hilft

GC.Collect() beansprucht nur den verwalteten .NET-Arbeitsspeicher zurück. Es zwingt Chromium nicht, nativen Speicher an das Betriebssystem zurückzugeben, und es reißt keine warmen BrowserPool-Tabs ab, die absichtlich am Leben erhalten werden, um wiederverwendet zu werden. Selbst bei korrekter Entsorgung und einer erzwungenen Sammlung können die von Task-Manager, Docker, Kubernetes oder Tools wie New Relic angezeigten Zahlen nicht sofort sinken.

Der Effekt ist am sichtbarsten in langlaufenden Anwendungen, gemeinsam genutzten Serverumgebungen und Docker- oder Kubernetes-Bereitstellungen. Für Java-Integrationen, die IronPdfEngine verwenden, tritt der Druck normalerweise im Engine-Prozess oder Container auf und nicht im JVM-Heap.

BrowserPool-Standardeinstellungen

IronPDF hält eine kleine Anzahl von Tabs zwischen den Rendern warm, um die Leistung zu verbessern. Die Standardeinstellungen sind:

  • BrowserPool.Enabled = true
  • BrowserPool.MaxIdleTabs = min(max(ProcessorCount / 2, 1), 4)
  • BrowserPool.IdleTimeoutSeconds = 30

Aufgrund dessen kann der Prozess auch ohne aktive Renderings 1 bis 4 inaktive Tabs kurzzeitig am Leben halten, wobei jeder nativen Speicher und Unterprozessressourcen hält, bis das Timeout verstreicht. Je nach dem gerenderten Inhalt und der Umgebung kann ein inaktiver Tab eine bemerkenswerte Menge behalten, etwa 50 bis 100 MB bei einigen Arbeitslasten. Diese erhöhte Basislinie kann etwa 30 Sekunden nach dem letzten Render bestehen bleiben, bevor sie stufenweise abfällt.

Lösung

Wenn Ihre Umgebung speicherbeschränkt ist, sind die BrowserPool-Einstellungen das Erste, was Sie anpassen sollten. Die Standardwerte sehen so aus:

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
$vbLabelText   $csharpLabel

Option 1: Deaktivieren Sie das Tab-Pooling komplett

Nutzen Sie dies, wenn Sie nach jedem Rendern die deterministischste Bereinigung wünschen.

renderer.RenderingOptions.BrowserPool.Enabled = false;
renderer.RenderingOptions.BrowserPool.Enabled = false;
renderer.RenderingOptions.BrowserPool.Enabled = False
$vbLabelText   $csharpLabel

Option 2: Halten Sie BrowserPool aktiviert, ohne inaktive Tabs zu behalten

Lässt die Funktion eingeschaltet, vermeidet aber das Halten von aktiven Tabs zwischen den Renderings, was eine deterministische Bereinigung pro Rendering ermöglicht.

renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 0;
renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 0;
$vbLabelText   $csharpLabel

Option 3: Reduzieren Sie das Timeout für inaktive Tabs

Ein Mittelweg: Behalten Sie einige Wiederverwendungsnutzen bei, lassen Sie den Speicher jedoch nach einem Datenverkehrsanstieg schneller freigegeben.

renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10;
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10;
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10
$vbLabelText   $csharpLabel

Auswahl zwischen ihnen:

  • Enabled = false: Arbeitsspeicherstabilität ist wichtiger als Aufwärm-Startleistung.
  • MaxIdleTabs = 0: Sie möchten eine deterministische Bereinigung pro Render ohne die Funktion vollständig zu deaktivieren.
  • Niedrigere IdleTimeoutSeconds: Ihre Arbeitslast tritt in Schüben auf und Sie möchten, dass Arbeitsspeicher nach jedem schneller beansprucht wird.

Strategien für lang laufende Anwendungen

Wenn Ihre Anwendung den Speicher konstant niedrig halten muss, arbeiten Sie diese Punkte in der Reihenfolge ab, beginnend mit dem Tuning von BrowserPool, bevor Sie zum Prozess-Recycling übergehen.

1. Begrenzen Sie gleichzeitiges Rendering

Mehrere gleichzeitig laufende Chromium-Render-Jobs erhöhen stark den Druck auf den nativen Speicher. Wenn Sie parallel rendern, begrenzen Sie, wie viele gleichzeitig mit einem Semaphor laufen können:

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
$vbLabelText   $csharpLabel

Umwickeln Sie Ihren IronPDF-Render-Aufruf im gedrosselten Bereich, sodass immer nur eine feste Anzahl von Jobs gleichzeitig ausgeführt wird.

2. Optimieren oder deaktivieren Sie BrowserPool

Für viele speicherempfindliche Bereitstellungen ist dies der effektivste erste Schritt. Deaktivieren Sie BrowserPool vollständig, setzen Sie MaxIdleTabs = 0, oder reduzieren Sie IdleTimeoutSeconds für burstige Arbeitslasten. Jede dieser Maßnahmen kann die anhaltende Post-Render-Basis verkleinern, ohne eine vollständige Neustartstrategie.

3. Isolieren Sie Rendering in einem separaten Worker

Das Auslagern des PDF-Renderings aus der Hauptanwendung ist ein starkes Muster für Produktionssysteme. Die Hauptanwendung bleibt stabil, der Rendering-Worker kann eigenständig neu gestartet werden, und der native Chromium-Speicher wird vollständig freigegeben, wenn dieser Worker beendet wird. Bevor Sie sich auf Recycling verlassen, bestätigen Sie, ob das Deaktivieren von BrowserPool oder das Setzen von MaxIdleTabs = 0 Ihnen bereits eine vorhersagbare Bereinigung pro Render gibt. Der Isolierungsansatz zahlt sich am meisten aus in Docker- oder Kubernetes-Umgebungen, Hintergrundjobsystemen und API-Plattformen, die eine striktere Speicherisolation benötigen.

4. Recyceln Sie den Worker nur bei Bedarf

Wenn eine harte Speichergrenze besteht und die Feinabstimmung von BrowserPool immer noch hinter den Erwartungen zurückbleibt, recyceln Sie den Rendering-Prozess oder Worker-Container nach einer festgelegten Anzahl von Jobs. Das könnte bedeuten, einen dedizierten Worker nach einer festen Batchgröße neu zu starten, Engine-Container in Kubernetes zu rotieren oder Rendering in einen eigenständig neustartbaren Dienst auszulagern. Betrachten Sie dies als späteren Schritt, nicht als Ihre erste Maßnahme.

Wann es sich um ein Leck handeln könnte

Erhöhter Speicher nach dem Rendern bedeutet nicht automatisch ein Leck. Chromium-basiertes Rendering hat zwei Arten von Wiederverwendung, die man verstehen muss: Allocator-Ebene Wiederverwendung, bei der Chromium intern native Speicherseiten reserviert (normal, nicht direkt steuerbar), und Tab-Ebene Wiederverwendung, bei der BrowserPool volle Tabs zwischen den Renderings am Leben hält (konfigurierbar, und oft der größere Beitrag zu dem, was man in Überwachungstools sieht).

Das Muster ist normalerweise erwartet, wenn der Speicher während des Renderings steigt, stabilisiert sich anstatt unbegrenzt zu wachsen, bleibt kurz danach erhöht und fällt später, wenn inaktive Tabs auslaufen oder für das nächste Rendering verfügbar bleiben.

Untersuchen Sie weiter, wenn:

  • Speicher wächst weiter, ohne sich unter einer ähnlichen Arbeitslast zu stabilisieren
  • Speicher wächst weiter, selbst nachdem die Parallelität reduziert wurde
  • Arbeitsspeicher wächst weiter, selbst nach dem Deaktivieren von BrowserPool oder dem Setzen von MaxIdleTabs = 0
  • Eine minimale Reproduktion zeigt das gleiche Muster über die Zeit mit kontrollierten Eingabedaten

Wann Sie den Support kontaktieren sollten

Wenden Sie sich an den technischen Support, wenn Sie alle folgenden Punkte reproduzieren können:

  1. Speicher wächst weiter, ohne sich unter einer kontrollierten Arbeitslast zu stabilisieren
  2. Das Problem bleibt nach Begrenzung der Parallelität bestehen
  3. Das Problem besteht fort, nachdem BrowserPool deaktiviert oder MaxIdleTabs = 0 gesetzt wurde
  4. Sie können es mit einem minimalen Beispielprojekt reproduzieren

Beim Öffnen eines Tickets sollten Sie Ihre IronPDF-Version, OS und Hosting-Umgebung, Docker- oder Kubernetes-Details, falls zutreffend, Programmiersprache, Renderfrequenz und Parallelitätsstufe, Speicherdiagramme oder Überwachungs-Screenshots und ein minimal reproduzierbares Beispiel einschließen.

Curtis Chau
Technischer Autor

Curtis Chau hat einen Bachelor-Abschluss in Informatik von der Carleton University und ist spezialisiert auf Frontend-Entwicklung mit Expertise in Node.js, TypeScript, JavaScript und React. Leidenschaftlich widmet er sich der Erstellung intuitiver und ästhetisch ansprechender Benutzerschnittstellen und arbeitet gerne mit modernen Frameworks sowie der Erstellung gut strukturierter, optisch ansprechender ...

Weiterlesen
Bereit anzufangen?
Nuget Downloads 20,296,129 | Version: 2026.7 gerade veröffentlicht
Still Scrolling Icon

Scrollst du immer noch?

Sie brauchen schnell einen Beweis? PM > Install-Package IronPdf
Führen Sie eine Probe aus Sehen Sie zu, wie Ihr HTML-Code in eine PDF-Datei umgewandelt wird.