Die beste Methode , mit diesem Problem umzugehen ist , die verwenden SetSystemFileCacheSize
API wie MS KB976618 anweist anweisen , verwendet .
Leeren Sie den Cache nicht regelmäßig
Wenn Sie die SetSystemFileCacheSize
Funktion verwenden, anstatt den Cache regelmäßig zu leeren, werden Leistung und Stabilität verbessert. Wenn der Cache regelmäßig geleert wird, werden zu viele Metadateien und andere Informationen aus dem Speicher entfernt, und Windows muss die erforderlichen Informationen erneut von der Festplatte in den Arbeitsspeicher zurücklesen. Dies führt zu einem plötzlichen und starken Leistungseinbruch für einige Sekunden, wenn Sie den Cache leeren, gefolgt von einer guten Leistung, die sich langsam verschlechtert, wenn sich der Speicher mit Metadateidaten füllt.
Durch die Verwendung der SetSystemFileCacheSize
Funktion werden Minimum und Maximum festgelegt, die dazu führen, dass Windows überschüssige alte Metadateidaten als Standby-Speicher kennzeichnet, den die normalen Caching-Funktionen je nach aktuellem Ressourcenbedarf und normalen Cache-Prioritäten verwenden oder verwerfen können. Dies ermöglicht auch, dass mehr Metadateidaten als der von Ihnen festgelegte Maximalwert für den aktiven Speicher als Standby-Daten gespeichert werden, wenn Windows den Speicher nicht für andere Zwecke verwendet, während genügend verfügbarer Speicher verfügbar bleibt. Dies ist die ideale Situation, um die Leistungseigenschaften des Systems jederzeit zu erhalten.
Programme von Drittanbietern werden von MS nicht unterstützt
Wenn Sie wie ich sind und keine Binärdatei von einem unbekannten Drittanbieter auf Ihren Produktionsservern ausführen möchten, benötigen Sie ein offizielles MS-Tool oder einen Code, den Sie überprüfen können, bevor Sie auf diesen Servern ausgeführt werden. Das DynCache-Tool für 2008 R2 ist ohne die Bezahlung eines Support-Falls praktisch nicht von M $ zu beziehen. Auf der Grundlage des Codes für 2008 scheint es für diese Aufgabe überlastet zu sein, da Windows bereits über die integrierte Logik verfügt, die für die dynamische Größe erforderlich ist der Cache - es muss nur ein angemessenes Maximum für Ihr System bekannt sein.
Lösung für alle oben genannten Probleme
Ich habe ein Powershell-Skript geschrieben, das auf 64-Bit-Computern funktioniert. Sie müssen es als Administrator mit erhöhten Rechten ausführen. Sie sollten in der Lage sein, es auf jedem x64-Windows Vista / Server 2008 bis einschließlich 10 / Server 2012 R2 mit beliebig viel RAM auszuführen. Sie müssen keine zusätzliche Software installieren und erhalten dadurch die vollständige Unterstützung Ihres Servers / Ihrer Workstation durch MS.
Sie sollten dieses Skript bei jedem Start mit erhöhten Rechten ausführen, damit die Einstellung dauerhaft ist. Windows Task Scheduler kann dies für Sie tun. Wenn sich die Windows-Installation in einer virtuellen Maschine befindet und Sie die dieser VM zugewiesene RAM-Größe ändern, sollten Sie sie auch nach der Änderung ausführen.
Sie können dieses Skript jederzeit auf einem laufenden System ausführen, auch wenn es in der Produktion verwendet wird, ohne das System neu starten oder Dienste herunterfahren zu müssen.
# 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
Oben in der Zeile steht, $MaxPercent = 12.5
dass der neue maximale Arbeitsspeicher (aktiver Speicher) auf 12,5% des gesamten physischen Arbeitsspeichers festgelegt wird. Windows passt die Größe der Metadateidaten im aktiven Speicher dynamisch an die Systemanforderungen an, sodass Sie dieses Maximum nicht dynamisch anpassen müssen.
Hierdurch werden keine Probleme behoben, die auftreten, wenn der zugeordnete Dateicache zu groß wird.
Ich habe auch ein GetSystemFileCacheSize
Powershell-Skript erstellt und auf StackOverflow veröffentlicht .
Bearbeiten: Ich möchte Sie auch darauf hinweisen, dass Sie keines dieser beiden Skripte mehr als einmal von derselben Powershell-Instanz ausführen sollten, da sonst die Fehlermeldung angezeigt wird, dass der Add-Type
Aufruf bereits erfolgt ist.
Bearbeiten: Aktualisiertes SetSystemFileCacheSize
Skript auf Version 1.1, das einen angemessenen maximalen Cache-Wert für Sie berechnet und ein besseres Layout für die Statusausgabe aufweist.
Bearbeiten: Nachdem ich mein Windows 7-Notebook aktualisiert habe, kann ich Ihnen mitteilen, dass das Skript unter Windows 10 erfolgreich ausgeführt wird, obwohl ich nicht getestet habe, ob es noch benötigt wird. Aber mein System ist immer noch stabil, selbst wenn ich Festplattendateien von virtuellen Maschinen verschiebe.