Sur certains serveurs Windows Server 2019, taskhostw.exe finit par monopoliser plusieurs Go de RAM au bout de semaines ou de mois. Peut‑on le plafonner ? Indirectement, oui. Voici un guide opérationnel pour stabiliser un serveur MSSQL + DCS sans interrompre la production.
Comprendre taskhostw.exe et les symptômes
taskhostw.exe (Task Host Windows) est un process host : il charge des composants DLL (services, tâches, handlers COM, plug‑ins d’impression, etc.) et exécute leur code dans son processus. Quand la consommation mémoire grimpe, taskhostw.exe n’est bien souvent que le conteneur ; la fuite réelle provient de la DLL qu’il héberge (pilote, add‑in, spooler, OPC/DA, plug‑in DCS…).
Symptômes typiques :
- Augmentation continue des Private Bytes de taskhostw.exe (fuite en espace utilisateur).
- Croissance du Paged Pool ou du Nonpaged Pool au niveau système (fuite noyau/driver).
- Concurrence avec SQL Server : le buffer pool monte au plafond, la mémoire libre s’écrase et le serveur devient lent (paging, latence disque, timeouts DCS).
Réponse courte
Il n’existe pas de quota mémoire « natif » dédié à taskhostw.exe dans Windows Server 2019. On peut toutefois encadrer sa dérive : maîtriser la mémoire SQL, déclencher plus tôt le trimming du pool paginé, identifier et corriger la DLL fautive, et à défaut, contraindre ou redémarrer proprement le service hébergé.
Plan d’action recommandé
Objectif | Mesures concrètes | Commentaires utiles |
---|---|---|
Réserver de la mémoire à SQL Server | – Fixer un MAX Server Memory adapté (laisser typiquement 4–6 Go à l’OS, aux pilotes et à DCS). – Ajuster MIN Server Memory pour lisser la montée en charge post‑reboot. – Vérifier l’alignement avec les jobs, index rebuild, SSIS/SSRS et autres composants. | Évite que SQL « aspire » toute la RAM libérée par taskhostw.exe. Stabilise l’ensemble du serveur. |
Activer une gestion agressive de l’épuisement noyau | Registre : HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management • PoolUsageMaximum = 60–70 % (DWORD : seuil de trimming).• PagedPoolSize = 0 (laisser Windows gérer dynamiquement). | Déclenche plus tôt la libération du Paged Pool et limite l’emballement des composants hébergés par taskhostw.exe. |
Identifier la DLL fautive (fuite mémoire) | – RAMMap : confirmer le type de fuite (Private Bytes vs Pools). – PoolMon : repérer le tag noyau qui croît. – Process Explorer : onglets Threads et Modules de taskhostw.exe pour isoler la DLL active. | taskhostw.exe n’est qu’un conteneur ; 9 fois sur 10, la fuite vient d’un pilote, d’un plug‑in d’impression, d’un handler OPC/DA ou d’un add‑in DCS. |
Relancer proprement le service fautif | – Dans Services : onglet Récupération → Redémarrer le service. – Planifier un redémarrage contrôlé mensuel si la haute disponibilité n’est pas critique (ou basculer via cluster). | Évite l’accumulation sur plusieurs mois quand aucun correctif n’est encore disponible. |
Limiter un processus comme dernier recours | – Job objects Windows (via script PowerShell/C#) pour imposer un commit limit au process. – Outils tiers (ex. Process Lasso) si la gouvernance interne l’autorise. | Peut provoquer une terminaison forcée si la limite est atteinte ; à réserver aux environnements maîtrisés. |
Mettre à jour et corriger | – Appliquer les mises à jour cumulatives récentes de Windows Server 2019. – Mettre à jour les pilotes, filtres d’impression, composants DCS/OPC/DA, agents de sauvegarde/antivirus. | Plusieurs fuites de pool paginé et de gestion mémoire ont été corrigées dans des mises à jour récentes. |
Dimensionner correctement SQL Server
SQL est souvent le principal consommateur de RAM. S’il n’est pas borné, il amplifie tout problème mémoire à côté. Définissez un plafond clair :
- Calculez la RAM à réserver à l’OS et aux services (pilotes, DCS, sauvegardes, antivirus). En pratique : 4–6 Go pour un serveur de 32–64 Go, davantage si beaucoup de pilotes/agents.
- Déduisez ce budget du total physique, et affectez‑le à max server memory.
Exemple (64 Go physiques, on réserve 6 Go à l’OS/DCS) : max server memory
≈ 58 Go.
-- À exécuter sur l'instance MSSQL
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'min server memory (MB)', 4096; -- à ajuster selon vos besoins
EXEC sp_configure 'max server memory (MB)', 59392; -- exemple pour ~58 Go
RECONFIGURE;
Surveillez ensuite Target Server Memory vs Total Server Memory (compteurs SQLServer:Buffer Manager) et adaptez au fil de l’eau (montées de version, nouveaux workloads DCS, etc.).
Configurer le trimming du pool paginé
Quand des pilotes fuient, c’est le Paged Pool qui gonfle. Vous pouvez demander à Windows de tailler plus tôt dans ce pool pour retarder la dégradation :
# Exécuter en PowerShell élevé
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" ^
/v PoolUsageMaximum /t REG_DWORD /d 70 /f
# Laisser Windows gérer dynamiquement la taille du paged pool (valeur par défaut)
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" ^
/v PagedPoolSize /t REG_DWORD /d 0 /f
Un redémarrage est recommandé après modification. Note : PagedPoolSize
laissé à 0
permet à Windows d’ajuster dynamiquement ; c’est généralement le meilleur choix en production.
Isoler la DLL ou le pilote qui fuit
Valider le type de fuite
- RAMMap : vérifiez si la croissance vient des Private Bytes de taskhostw.exe (fuite user‑mode), ou des pools noyau (fuite kernel‑mode).
- PerfMon : suivez
\Process(taskhostw)\Private Bytes
,\Memory\Pool Paged Bytes
,\Memory\Pool Nonpaged Bytes
.
Analyser taskhostw.exe
- Avec Process Explorer, ouvrez les Properties de taskhostw.exe :
- Threads : regardez les Start Address et la Module Path des threads les plus actifs.
- Modules : repérez les DLL non Microsoft chargées (impression, DCS/OPC, sauvegarde, antivirus).
Chasser une fuite noyau avec PoolMon
- Activez le pool tagging :
gflags /r +ptg
, puis redémarrez. - Lancez PoolMon :
poolmon -b -p
et triez par Bytes. - Notez le tag qui croît, puis mappez‑le au pilote (via la table des tags du WDK ou la colonne Owner si disponible).
Une fois la DLL/le pilote identifié, mettez‑le à jour, remplacez‑le, ou contactez l’éditeur. C’est la solution durable.
Relancer automatiquement le composant fautif
Si la DLL appartient à un service Windows distinct, configurez une récupération automatique :
sc failure <NomDuService> reset= 86400 actions= restart/60000/restart/60000//
sc failureflag <NomDuService> 1
Vous pouvez aussi créer une tâche planifiée qui surveille la mémoire et redémarre le service au‑delà d’un seuil :
# Exemple : redémarrer le service si taskhostw.exe > 1.5 Go de Private Bytes
$threshold = 1.5GB
$proc = Get-Process -Name taskhostw -ErrorAction SilentlyContinue
if ($proc -and $proc.PrivateMemorySize64 -gt $threshold) {
Restart-Service -Name <NomDuServiceLieAlaDLL> -Force -ErrorAction Stop
}
Limiter par job object : solution avancée
Windows permet d’associer un processus à un job object et de lui imposer une limite de mémoire engagée (commit). En cas de dépassement, le processus est terminé par le noyau. À utiliser avec prudence, en pré‑production d’abord.
# PowerShell + C# inline (exemple simplifié)
$code = @"
using System;
using System.Runtime.InteropServices;
public static class JobLimit {
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetInformationJobObject(IntPtr hJob, int JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);
const int JobObjectExtendedLimitInformation = 9;
const uint PROCESS_ALL_ACCESS = 0x1F0FFF;
const int JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200;
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION {
public long PerProcessUserTimeLimit;
public long PerJobUserTimeLimit;
public int LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public int ActiveProcessLimit;
public long Affinity;
public int PriorityClass;
public int SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS {
public ulong ReadOperationCount;
public ulong WriteOperationCount;
public ulong OtherOperationCount;
public ulong ReadTransferCount;
public ulong WriteTransferCount;
public ulong OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}
public static void CapProcessMemory(int pid, ulong jobMemoryLimitBytes) {
IntPtr hJob = CreateJobObject(IntPtr.Zero, "TaskHost_Cap");
var info = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY;
info.JobMemoryLimit = (UIntPtr)jobMemoryLimitBytes;
int size = Marshal.SizeOf(info);
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(info, ptr, false);
if (!SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, ptr, (uint)size)) {
throw new System.ComponentModel.Win32Exception();
}
IntPtr hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
if (!AssignProcessToJobObject(hJob, hProc)) {
throw new System.ComponentModel.Win32Exception();
}
Marshal.FreeHGlobal(ptr);
}
}
"@
Add-Type -TypeDefinition $code
# Exemple : limite globale à 2 Go pour le job contenant taskhostw.exe
$proc = Get-Process -Name taskhostw -ErrorAction Stop
[JobLimit]::CapProcessMemory($proc.Id, 2GB)
Write-Host "Limite de mémoire appliquée. Attention : dépassement = terminaison par le noyau."
Attention : si la DLL continue de fuir, vous finirez par tuer un composant système hébergé par taskhostw.exe. À réserver aux environnements où un redémarrage automatique du service impacté est acceptable.
Surveillance proactive et alertes
Installez une collecte continue pour être alerté bien avant la saturation :
Compteur PerfMon | Seuil indicatif | Signal |
---|---|---|
\Process(taskhostw)\Private Bytes | > 1 Go sur > 30 min | Fuite user‑mode probable dans une DLL hébergée |
\Memory\Pool Paged Bytes | Hausse continue > 30 % | Fuite noyau/driver (impression, filtre, antivirus…) |
\SQLServer:Buffer Manager\Total Server Memory | ≈ Target Server Memory | SQL a atteint son plafond ; OK si Target calculé justement |
\Memory\Available MBytes | < 10 % de la RAM | Forte pression mémoire ; risque de paging |
Création rapide d’un collecteur en ligne de commande :
logman create counter TaskhostwLeak ^
-c "\Process(taskhostw)\Private Bytes" "\Memory\Pool Paged Bytes" ^
-si 00:01:00 -o C:\PerfLogs\Taskhostw.blg -f bin -v mmddhhmm
logman start TaskhostwLeak
Capturer des preuves avant correction
Avant d’ouvrir un ticket éditeur, capturez :
- ProcDump de taskhostw.exe sur seuil de croissance (pour une fuite user‑mode).
- PoolMon + captures RAMMap (pour une fuite noyau).
- Journaux Application et Système (Event Viewer) : erreurs d’impression, filtres, pilotes, DCS/OPC, antivirus.
:: Capture d'un dump complet quand la mémoire dépasse un seuil
procdump -ma -s 30 -n 3 -x C:\Dumps taskhostw.exe
Bonnes pratiques de maintenance
- Mettre à jour Windows Server 2019 (dernières CU), pilotes, filtreurs d’impression, composants DCS/OPC/DA, agents de sauvegarde/antivirus.
- Éviter les add‑ins non indispensables côté impression/DCS, surtout sur les serveurs SQL.
- Planifier un redémarrage contrôlé périodique si l’application métier le tolère, le temps de disposer d’un correctif.
- Segmenter les rôles quand c’est possible : un serveur SQL dédié et un serveur DCS/OPC séparé limitent les effets de bord.
FAQ
Augmenter la RAM règle‑t‑il le problème ?
Non. Cela retarde l’échéance mais ne corrige pas la fuite. Préférez corriger la DLL fautive et fixer un plafond SQL robuste.
Peut‑on désactiver taskhostw.exe ?
Non. C’est un composant du système. Travaillez plutôt à isoler la DLL ou le service en cause.
Vider le working set de taskhostw.exe aide‑t‑il ?
Parfois, ponctuellement. Mais si la fuite est du commit ou du pool noyau, l’effet est temporaire.
Ressource Manager peut‑il aider ?
Le gestionnaire de ressources historique de Windows n’est plus disponible sur Windows Server 2019. Utilisez des job objects ou des outils tiers si vous devez imposer une limite.
Checklist de terrain
- Appliquez les mises à jour Windows et des pilotes.
- Fixez max server memory de SQL et vérifiez min server memory.
- Activez
PoolUsageMaximum
et redémarrez si nécessaire. - Surveillez
Private Bytes
de taskhostw.exe et les pools noyau. - Avec RAMMap/PoolMon/Process Explorer, identifiez la DLL/le driver.
- Mettez à jour, remplacez, ou isolez la pièce fautive.
- Configurez la récupération du service et des alertes.
- En dernier recours, limitez par job object en pré‑prod, puis en prod si validé.
Points clés à retenir
- Pas de quota natif pour taskhostw.exe : le plafonnement se fait via la maîtrise de SQL, le trimming noyau, les correctifs et, au pire, un job object.
- Traitez la cause : identifiez et mettez à jour la DLL/driver qui fuit. C’est la solution durable.
- Gardez SQL sous contrôle : un max server memory bien fixé stabilise tout l’écosystème.
- Surveillez en continu et alertez tôt pour éviter les arrêts non planifiés.
Annexes : commandes prêtes à l’emploi
Afficher les compteurs clés en temps réel
Get-Counter "\Process(taskhostw)\Private Bytes","\Memory\Pool Paged Bytes","\Memory\Available MBytes" -SampleInterval 5 -MaxSamples 12
Lister les modules non Microsoft chargés par taskhostw.exe
$p = Get-Process -Name taskhostw -ErrorAction Stop
(Get-Process -Id $p.Id -Module | Where-Object { $_.FileVersionInfo.CompanyName -notlike "*Microsoft*" }) |
Select-Object FileName, @{n="Company";e={$_.FileVersionInfo.CompanyName}}
Forcer une récupération de service si dépassement
$threshold = 1GB
$svc = "<NomDuServiceLieAlaDLL>"
$p = Get-Process taskhostw -ErrorAction SilentlyContinue
if ($p -and $p.PrivateMemorySize64 -gt $threshold) {
Write-EventLog -LogName Application -Source "MemoryGuard" -EntryType Warning -EventId 9001 -Message "taskhostw.exe dépasse $threshold, redémarrage du service $svc"
Restart-Service -Name $svc -Force
}
En appliquant ces bonnes pratiques, vous gardez la consommation mémoire de taskhostw.exe sous contrôle sans compromettre la stabilité de votre serveur Windows Server 2019 dédié à SQL Server et à votre environnement DCS.