이 문제를 처리하는 가장 좋은 방법은 SetSystemFileCacheSize
API를 MS KB976618 명령에 지시 하는 데 사용하는 것 입니다.
캐시를 주기적으로 지우지 마십시오
SetSystemFileCacheSize
캐시를 지우지 않고 기능을 사용 하면 성능과 안정성이 향상됩니다. 캐시를 주기적으로 지우면 메모리에서 메타 파일 및 기타 정보가 너무 많이 제거되고 Windows에서 필요한 정보를 HDD에서 RAM으로 다시 읽어야합니다. 이렇게하면 캐시를 지울 때마다 몇 초 동안 갑자기 성능이 저하되고 메모리가 메타 파일 데이터로 가득 차면 성능이 저하됩니다.
이 SetSystemFileCacheSize
기능을 사용하면 Windows에서 초과 된 오래된 메타 파일 데이터를 대기 메모리로 플래그 지정하여 일반 캐싱 기능이 현재 자원 요구 및 일반 캐시 우선 순위에 따라 사용하거나 삭제할 수있는 최소값과 최대 값을 설정합니다. 또한 Windows에서 사용 가능한 메모리를 많이 유지하면서 다른 용도로 메모리를 사용하지 않는 경우 설정 한 활성 메모리 최대 값보다 많은 메타 파일 데이터를 대기 데이터로 사용할 수 있습니다. 이것은 시스템의 성능 특성을 항상 양호하게 유지하는 이상적인 상황입니다.
MS는 타사 프로그램을 지원하지 않습니다
나와 같은데 프로덕션 서버에서 알려지지 않은 타사의 바이너리를 실행하지 않으려면 공식 MS 도구 또는 해당 서버에서 실행하기 전에 검사 할 수있는 코드가 필요합니다. 2008 R2 용 DynCache 도구는 지원 사례에 대한 비용을 지불하지 않고 M $에서 구할 수 없으며 2008 년 코드를 기반으로 솔직히 말해서 Windows가 이미 동적 크기 조정에 필요한 내장 논리를 가지고 있기 때문에 작업에 과장된 것처럼 보입니다. 캐시 — 시스템에 적절한 최대 값 만 알고 있으면됩니다.
위의 모든 솔루션
64 비트 컴퓨터에서 작동하는 Powershell 스크립트를 작성했습니다. 관리자 권한으로 관리자 권한으로 실행해야합니다. 모든 크기의 RAM이있는 10 / Server 2012 R2를 포함하여 모든 x64 Windows Vista / Server 2008에서 그대로 실행할 수 있어야합니다. 추가 소프트웨어를 설치할 필요가 없으므로 MS가 서버 / 워크 스테이션을 완벽하게 지원하십시오.
설정을 영구적으로 유지하려면 높은 권한으로 부팅 할 때마다이 스크립트를 실행해야합니다. Windows 작업 스케줄러가이를 수행 할 수 있습니다. Windows 설치가 가상 머신 내에 있고 해당 VM에 할당 된 RAM의 양을 변경하는 경우 변경 후에도 실행해야합니다.
시스템을 재부트하거나 서비스를 종료하지 않고도 프로덕션 사용 중에도 언제든지 실행중인 시스템에서이 스크립트를 실행할 수 있습니다.
# 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
$MaxPercent = 12.5
새로운 최대 작업 세트 (활성 메모리)를 총 실제 RAM의 12.5 %로 설정하는 라인이 맨 위에 있습니다. Windows는 시스템 요구에 따라 활성 메모리의 메타 파일 데이터 크기를 동적으로 조정하므로이 최대 값을 동적으로 조정할 필요가 없습니다.
매핑 된 파일 캐시가 너무 커지는 문제는 해결되지 않습니다.
또한 GetSystemFileCacheSize
Powershell 스크립트를 작성 하여 StackOverflow에 게시했습니다 .
편집 : 또한 동일한 Powershell 인스턴스 에서이 두 스크립트 중 하나를 두 번 이상 실행해서는 안되며 Add-Type
호출이 이미 작성되었다는 오류가 표시됩니다 .
편집 : SetSystemFileCacheSize
적절한 최대 캐시 값을 계산하고 상태 출력 레이아웃이 더 좋은 스크립트를 버전 1.1로 업데이트했습니다 .
편집 : 이제 Windows 7 랩톱을 업그레이드했는데 스크립트가 여전히 필요한지 테스트하지는 않았지만 Windows 10에서 스크립트가 성공적으로 실행된다는 것을 알 수 있습니다. 그러나 가상 시스템 HDD 파일을 옮기더라도 시스템은 여전히 안정적입니다.