Utilisation de la mémoire CEF/Chromium dans les applications longue durée
IronPDF fonctionne avec Chromium, de sorte que la mémoire du processus peut rester élevée pendant une courte période après la génération du PDF, même lorsque les documents sont supprimés et que GC.Collect() est exécuté. Deux sources sont en jeu: l'allocation native non gérée de Chromium et la mise en commun d'onglets du navigateur IronPDF. Dans la plupart des cas, c'est attendu, et cela ne signifie pas nécessairement qu'il y a une fuite de mémoire.
Cela s'applique à IronPDF et IronPdfEngine sur Windows et Linux, dans les environnements Docker, Kubernetes, VM, et hébergés sur serveur, ainsi qu'à .NET, Java, et toute application utilisant le rendu basé sur Chromium.
Pourquoi la mémoire reste élevée
Deux mécanismes distincts maintiennent la mémoire élevée après la fin d'un rendu.
Rétention de l'allocation native Chromium: Chromium utilise une grande quantité de mémoire non gérée qui vit en dehors du collecteur de déchets .NET. Lorsqu'un rendu est terminé, Chromium garde souvent cette mémoire native réservée pour une réutilisation plutôt que de la retourner immédiatement au système d'exploitation. Ainsi, vos objets PdfDocument peuvent être correctement supprimés, le runtime peut collecter les objets gérés, et la mémoire globale du processus ou du conteneur peut encore être élevée. C'est normal pour les moteurs basés sur Chromium.
Réutilisation des onglets BrowserPool: IronPDF peut garder les onglets de navigateur inactifs en vie après un rendu pour que le suivant démarre plus rapidement. Ces onglets conservent leurs sous-processus de rendu et état du DOM pendant un court instant, créant une ligne de base de mémoire visible même lorsque rien n'est en cours de rendu. Avec la mise en pool activée, vous verrez généralement la mémoire augmenter pendant le rendu, se maintenir à une ligne de base après la fin, puis diminuer par étapes à mesure que les onglets inactifs s'expirent et sont récoltés.
Pourquoi GC.Collect() n'aide pas
GC.Collect() ne récupère que la mémoire .NET gérée. Il ne force pas Chromium à rendre la mémoire native au système d'exploitation, et il ne détruit pas les onglets de BrowserPool chauds qui sont intentionnellement maintenus vivants pour réutilisation. Même avec une destruction correcte et une collecte forcée, les chiffres affichés par le Gestionnaire des tâches, Docker, Kubernetes, ou des outils comme New Relic peuvent ne pas baisser immédiatement.
L'effet est le plus visible dans les applications longue durée, les environnements de services partagés, et les déploiements Docker ou Kubernetes. Pour les intégrations Java utilisant IronPdfEngine, la pression apparaît généralement dans le processus ou le conteneur moteur plutôt que dans le tas JVM.
Paramètres par défaut de BrowserPool
IronPDF garde un petit nombre d'onglets chauds entre les rendus pour améliorer la performance. Les valeurs par défaut sont :
BrowserPool.Enabled = trueBrowserPool.MaxIdleTabs = min(max(ProcessorCount / 2, 1), 4)BrowserPool.IdleTimeoutSeconds = 30
À cause de cela, même sans rendus actifs, le processus peut garder 1 à 4 onglets inactifs vivants pour un bref instant, chacun tenant mémoire native et ressources de sous-processus jusqu'à expiration du délai d'inactivité. Selon le contenu rendu et l'environnement, un onglet inactif peut retenir une quantité notable, environ 50 à 100 Mo dans certaines charges de travail. Cette base élevée peut persister environ 30 secondes après le dernier rendu avant de diminuer par étapes.
Solution
Si votre environnement est contraint en mémoire, les paramètres de BrowserPool sont la première chose à ajuster. Les valeurs par défaut ressemblent à ceci :
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
Option 1 : Désactiver complètement la mise en pool des onglets
Choisissez cela lorsque vous souhaitez le nettoyage le plus déterministe après chaque rendu.
renderer.RenderingOptions.BrowserPool.Enabled = false;
renderer.RenderingOptions.BrowserPool.Enabled = false;
renderer.RenderingOptions.BrowserPool.Enabled = False
Option 2 : Gardez BrowserPool activé sans conserver les onglets inactifs
Laisse la fonction active mais évite de conserver les onglets chauds entre les rendus, donnant un nettoyage déterministe par rendu.
renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 0;
renderer.RenderingOptions.BrowserPool.MaxIdleTabs = 0;
Option 3: Réduisez le temps d'inactivité
Un juste milieu : conservez certains bénéfices de réutilisation, mais laissez la mémoire chuter plus tôt après un trafic en rafales.
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10;
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10;
renderer.RenderingOptions.BrowserPool.IdleTimeoutSeconds = 10
Choisir entre eux :
Enabled = false: la stabilité de la mémoire est plus importante que la performance de démarrage à chaud.MaxIdleTabs = 0: vous souhaitez un nettoyage déterministe par rendu sans désactiver complètement la fonctionnalité.- Réduire
IdleTimeoutSeconds: votre charge de travail arrive par rafales et vous souhaitez que la mémoire soit libérée plus tôt après chacune.
Stratégies pour les applications longue durée
Si votre application doit maintenir la mémoire constamment basse, suivez ces étapes dans l'ordre en commençant par l'ajustement de BrowserPool avant d'opter pour le recyclage des processus.
1. Limiter le rendu simultané
Plusieurs travaux de rendu Chromium exécutés en même temps augmentent considérablement la pression sur la mémoire native. Si vous effectuez un rendu en parallèle, limitez le nombre de rendus simultanés avec un sémaphore :
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
Enveloppez votre appel de rendu IronPDF à l'intérieur de la section limitée afin que seuls un nombre fixe de travaux s'exécutent à la fois.
2. Ajuster ou désactiver BrowserPool
Pour de nombreux déploiements sensibles à la mémoire, c'est la première étape la plus efficace. Désactivez complètement BrowserPool, définissez MaxIdleTabs = 0, ou réduisez IdleTimeoutSeconds pour les charges de travail par rafales. N'importe laquelle de ces options peut réduire la ligne de base post-rendu persistante sans une stratégie de redémarrage complète.
3. Isoler le rendu dans un travailleur séparé
Déplacer le rendu PDF hors de l'application principale est un modèle fort pour les systèmes de production. L'application principale reste stable, le travailleur de rendu peut être redémarré seul, et la mémoire native de Chromium est entièrement libérée lorsque ce travailleur se termine. Avant de vous fier au recyclage, confirmez si la désactivation de BrowserPool ou la définition de MaxIdleTabs = 0 vous offre déjà un nettoyage prévisible par rendu. L'approche d'isolation est la plus bénéfique dans les environnements Docker ou Kubernetes, les systèmes de travaux en arrière-plan, et les plateformes API nécessitant une isolation mémoire plus stricte.
4. Recycler le travailleur uniquement si nécessaire
Lorsque la mémoire atteint un plafond dur et que l'ajustement de BrowserPool ne suffit toujours pas, recyclez le processus de rendu ou le conteneur travailleur après un certain nombre de travaux. Cela peut signifier redémarrer un travailleur dédié après une taille de lot fixe, faire tourner les conteneurs du moteur dans Kubernetes, ou isoler le rendu dans un service qui peut redémarrer indépendamment. Considérez cela comme une étape ultérieure, pas votre première option.
Quand cela peut être une fuite
Une élévation de mémoire après un rendu ne signifie pas automatiquement une fuite. Le rendu basé sur Chromium a deux types de réutilisation à comprendre : la réutilisation au niveau de l'allocation, où Chromium réserve des pages de mémoire native en interne (normal, non directement contrôlable), et la réutilisation au niveau des onglets, où BrowserPool garde les onglets intacts entre les rendus (configurable, et souvent le plus grand contributeur de ce que vous voyez dans les outils de surveillance).
Le schéma est généralement attendu lorsque la mémoire augmente pendant le rendu, se stabilise au lieu de croître indéfiniment, reste élevée brièvement après, puis baisse lorsque les onglets inactifs expirent ou restent disponibles pour le prochain rendu.
Investiguez davantage lorsque :
- la mémoire continue d'augmenter sans se stabiliser sous une charge de travail similaire
- la mémoire continue de croître même après avoir réduit la concurrence
- la mémoire continue de croître même après la désactivation de BrowserPool ou la définition de
MaxIdleTabs = 0 - une reproduction minimale montre le même schéma dans le temps avec des données d'entrée contrôlées
Quand contacter le support
Contactez le support technique si vous pouvez reproduire toutes les conditions suivantes :
- la mémoire continue de croître sans se stabiliser sous une charge de travail contrôlée
- le problème persiste après avoir limité la concurrence
- le problème persiste après la désactivation de BrowserPool ou la définition de
MaxIdleTabs = 0 - vous pouvez le reproduire avec un projet d'échantillon minimal
Lors de l'ouverture d'un ticket, incluez votre version d'IronPDF, le système d'exploitation et l'environnement d'hébergement, les détails Docker ou Kubernetes si applicable, le langage de programmation, la fréquence de rendu et le niveau de concurrence, les graphiques de mémoire ou les captures d'écran de surveillance, et un échantillon minimal reproductible.

