La meilleure méthode pour traiter ce problème consiste à utiliser l' SetSystemFileCacheSize
API en suivant les instructions de MS KB976618 utilisées .
Ne pas vider le cache périodiquement
L'utilisation de la SetSystemFileCacheSize
fonction plutôt que la suppression du cache améliore périodiquement les performances et la stabilité. Si vous effacez le cache périodiquement, trop de métafichiers et d’autres informations seront purgés de la mémoire. Windows devra alors relire les informations requises dans la RAM du disque dur. Cela entraîne une baisse soudaine et sévère des performances pendant plusieurs secondes chaque fois que vous effacez le cache, suivie d'une performance satisfaisante qui se dégrade lentement à mesure que la mémoire se remplit de données de métafichier.
L'utilisation des SetSystemFileCacheSize
fonctions définit les valeurs minimale et maximale qui permettront à Windows de marquer les anciennes données de métafichier en excès comme mémoire de secours que les fonctions de mise en cache normales peuvent utiliser ou rejeter en fonction des demandes de ressources actuelles et des priorités de mémoire cache normales. Cela permet également à plus de métafichiers que le maximum de mémoire active défini de rester en mémoire en tant que données en attente si Windows n'utilise pas la mémoire pour autre chose, tout en conservant une grande quantité de mémoire disponible. Il s’agit de la situation idéale pour maintenir les performances du système en permanence.
Les programmes tiers ne sont pas pris en charge par MS
Si vous êtes comme moi et que vous ne souhaitez pas exécuter un fichier binaire provenant d'un tiers inconnu sur vos serveurs de production, vous souhaitez un outil MS officiel ou un code que vous pouvez inspecter avant de l'exécuter sur ces serveurs. L'outil DynCache pour 2008 R2 est pratiquement impossible à obtenir auprès de M $ sans avoir à payer pour une demande d'assistance et, très franchement, basé sur le code de 2008, il semble excessivement lourd pour la tâche, car Windows dispose déjà de la logique intégrée nécessaire pour dimensionner de manière dynamique. le cache - il suffit de connaître un maximum approprié pour votre système.
Solution à tout ce qui précède
J'ai écrit un script Powershell qui fonctionne sur des machines 64 bits. Vous devez l'exécuter en tant qu'administrateur avec des privilèges élevés. Vous devriez pouvoir l'exécuter, tel quel, sur tout ordinateur Windows Vista / Server 2008 x64 jusqu'à 10 / Server 2012 R2 inclus, avec n'importe quelle quantité de RAM. Vous n'avez pas besoin d'installer de logiciel supplémentaire. Par conséquent, maintenez votre serveur / poste de travail entièrement pris en charge par MS.
Vous devez exécuter ce script à chaque démarrage avec des privilèges élevés pour que le paramètre soit permanent. Le Planificateur de tâches Windows peut le faire pour vous. Si l'installation Windows se trouve sur une machine virtuelle et que vous modifiez la quantité de RAM allouée à cette machine virtuelle, vous devez également l'exécuter après la modification.
Vous pouvez exécuter ce script à tout moment sur un système en fonctionnement, même en cours de production, sans avoir à redémarrer le système ou à arrêter tous les services.
# Filename: setfc.ps1
$version = 1.1
#########################
# Settings
#########################
# The percentage of physical ram that will be used for SetSystemFileCache Maximum
$MaxPercent = 12.5
#########################
# Init multipliers
#########################
$OSBits = ([System.IntPtr]::Size) * 8
switch ( $OSBits)
{
32 { $KiB = [int]1024 }
64 { $KiB = [long]1024 }
default {
# not 32 or 64 bit OS. what are you doing??
$KiB = 1024 # and hope it works anyway
write-output "You have a weird OS which is $OSBits bit. Having a go anyway."
}
}
# These values "inherit" the data type from $KiB
$MiB = 1024 * $KiB
$GiB = 1024 * $MiB
$TiB = 1024 * $GiB
$PiB = 1024 * $TiB
$EiB = 1024 * $PiB
#########################
# Calculated Settings
#########################
# Note that because we are using signed integers instead of unsigned
# these values are "limited" to 2 GiB or 8 EiB for 32/64 bit OSes respectively
$PhysicalRam = 0
$PhysicalRam = [long](invoke-expression (((get-wmiobject -class "win32_physicalmemory").Capacity) -join '+'))
if ( -not $? ) {
write-output "Trying another method of detecting amount of installed RAM."
}
if ($PhysicalRam -eq 0) {
$PhysicalRam = [long]((Get-WmiObject -Class Win32_ComputerSystem).TotalPhysicalMemory) # gives value a bit less than actual
}
if ($PhysicalRam -eq 0) {
write-error "Cannot Detect Physical Ram Installed. Assuming 4 GiB."
$PhysicalRam = 4 * $GiB
}
$NewMax = [long]($PhysicalRam * 0.01 * $MaxPercent)
# The default value
# $NewMax = 1 * $TiB
#########################
# constants
#########################
# Flags bits
$FILE_CACHE_MAX_HARD_ENABLE = 1
$FILE_CACHE_MAX_HARD_DISABLE = 2
$FILE_CACHE_MIN_HARD_ENABLE = 4
$FILE_CACHE_MIN_HARD_DISABLE = 8
################################
# C# code
# for interface to kernel32.dll
################################
$source = @"
using System;
using System.Runtime.InteropServices;
namespace MyTools
{
public static class cache
{
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool GetSystemFileCacheSize(
ref IntPtr lpMinimumFileCacheSize,
ref IntPtr lpMaximumFileCacheSize,
ref IntPtr lpFlags
);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetSystemFileCacheSize(
IntPtr MinimumFileCacheSize,
IntPtr MaximumFileCacheSize,
Int32 Flags
);
[DllImport("kernel32", CharSet = CharSet.Unicode)]
public static extern int GetLastError();
public static bool Get( ref IntPtr a, ref IntPtr c, ref IntPtr d )
{
IntPtr lpMinimumFileCacheSize = IntPtr.Zero;
IntPtr lpMaximumFileCacheSize = IntPtr.Zero;
IntPtr lpFlags = IntPtr.Zero;
bool b = GetSystemFileCacheSize(ref lpMinimumFileCacheSize, ref lpMaximumFileCacheSize, ref lpFlags);
a = lpMinimumFileCacheSize;
c = lpMaximumFileCacheSize;
d = lpFlags;
return b;
}
public static bool Set( IntPtr MinimumFileCacheSize, IntPtr MaximumFileCacheSize, Int32 Flags )
{
bool b = SetSystemFileCacheSize( MinimumFileCacheSize, MaximumFileCacheSize, Flags );
if ( !b ) {
Console.Write("SetSystemFileCacheSize returned Error with GetLastError = ");
Console.WriteLine( GetLastError() );
}
return b;
}
}
public class AdjPriv
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable)
{
tp.Attr = SE_PRIVILEGE_DISABLED;
} else {
tp.Attr = SE_PRIVILEGE_ENABLED;
}
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
}
}
"@
# Add the c# code to the powershell type definitions
Add-Type -TypeDefinition $source -Language CSharp
#########################
# Powershell Functions
#########################
function output-flags ($flags)
{
Write-output ("FILE_CACHE_MAX_HARD_ENABLE : " + (($flags -band $FILE_CACHE_MAX_HARD_ENABLE) -gt 0) )
Write-output ("FILE_CACHE_MAX_HARD_DISABLE : " + (($flags -band $FILE_CACHE_MAX_HARD_DISABLE) -gt 0) )
Write-output ("FILE_CACHE_MIN_HARD_ENABLE : " + (($flags -band $FILE_CACHE_MIN_HARD_ENABLE) -gt 0) )
Write-output ("FILE_CACHE_MIN_HARD_DISABLE : " + (($flags -band $FILE_CACHE_MIN_HARD_DISABLE) -gt 0) )
write-output ""
}
#########################
# Main program
#########################
write-output ""
#########################
# Get and set privilege info
$ProcessId = $pid
$processHandle = (Get-Process -id $ProcessId).Handle
$Privilege = "SeIncreaseQuotaPrivilege"
$Disable = $false
Write-output ("Enabling SE_INCREASE_QUOTA_NAME status: " + [MyTools.AdjPriv]::EnablePrivilege($processHandle, $Privilege, $Disable) )
write-output ("Program has elevated privledges: " + ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") )
write-output ""
whoami /PRIV | findstr /I "SeIncreaseQuotaPrivilege" | findstr /I "Enabled"
if ( -not $? ) {
write-error "user Security Token SE_INCREASE_QUOTA_NAME: Disabled`r`n"
}
write-output "`r`n"
#########################
# Get Current Settings
# Init variables
$SFCMin = 0
$SFCMax = 0
$SFCFlags = 0
#Get Current values from kernel
$status = [MyTools.cache]::Get( [ref]$SFCMin, [ref]$SFCMax, [ref]$SFCFlags )
#typecast values so we can do some math with them
$SFCMin = [long]$SFCMin
$SFCMax = [long]$SFCMax
$SFCFlags = [long]$SFCFlags
write-output "Return values from GetSystemFileCacheSize are: "
write-output "Function Result : $status"
write-output " Min : $SFCMin"
write-output (" Max : $SFCMax ( " + $SFCMax / 1024 / 1024 / 1024 + " GiB )")
write-output " Flags : $SFCFlags"
output-flags $SFCFlags
#########################
# Output our intentions
write-output ("Physical Memory Detected : $PhysicalRam ( " + $PhysicalRam / $GiB + " GiB )")
write-output ("Setting Max to " + $MaxPercent + "% : $NewMax ( " + $NewMax / $MiB + " MiB )`r`n")
#########################
# Set new settings
$SFCFlags = $SFCFlags -bor $FILE_CACHE_MAX_HARD_ENABLE # set max enabled
$SFCFlags = $SFCFlags -band (-bnot $FILE_CACHE_MAX_HARD_DISABLE) # unset max dissabled if set
# or if you want to override this calculated value
# $SFCFlags = 0
$status = [MyTools.cache]::Set( $SFCMin, $NewMax, $SFCFlags ) # calls the c# routine that makes the kernel API call
write-output "Set function returned: $status`r`n"
# if it was successfull the new SystemFileCache maximum will be NewMax
if ( $status ) {
$SFCMax = $NewMax
}
#########################
# After setting the new values, get them back from the system to confirm
# Re-Init variables
$SFCMin = 0
$SFCMax = 0
$SFCFlags = 0
#Get Current values from kernel
$status = [MyTools.cache]::Get( [ref]$SFCMin, [ref]$SFCMax, [ref]$SFCFlags )
#typecast values so we can do some math with them
$SFCMin = [long]$SFCMin
$SFCMax = [long]$SFCMax
$SFCFlags = [long]$SFCFlags
write-output "Return values from GetSystemFileCacheSize are: "
write-output "Function Result : $status"
write-output " Min : $SFCMin"
write-output (" Max : $SFCMax ( " + $SFCMax / 1024 / 1024 / 1024 + " GiB )")
write-output " Flags : $SFCFlags"
output-flags $SFCFlags
Une ligne vers le haut indique $MaxPercent = 12.5
que le nouvel ensemble de travail maximal (mémoire active) est défini sur 12,5% de la RAM physique totale. Windows dimensionnera dynamiquement la quantité de métafichiers dans la mémoire active en fonction des exigences du système. Vous n'avez donc pas besoin d'ajuster dynamiquement ce maximum.
Cela ne résoudra pas les problèmes que vous avez avec le cache de fichiers mappé qui devient trop gros.
J'ai également créé un GetSystemFileCacheSize
script Powershell et l' ai posté sur StackOverflow .
Edit: Je dois également signaler que vous ne devez exécuter aucun de ces 2 scripts à partir de la même instance Powershell plusieurs fois, sinon vous recevrez le Add-Type
message d' erreur indiquant que l' appel a déjà été passé.
Edit: SetSystemFileCacheSize
script mis à jour vers la version 1.1 qui calcule une valeur de cache maximale appropriée pour vous et présente une présentation de sortie de statut plus agréable.
Edit: Maintenant que j'ai mis à niveau mon ordinateur portable Windows 7, je peux vous dire que le script s'exécute correctement dans Windows 10, bien que je n'ai pas encore vérifié s'il était toujours nécessaire. Mais mon système reste stable même lorsque je déplace des fichiers HDD de machines virtuelles.