windows-server-2008-r2 – Windows Server 2008 R2图元文件RAM

我有一台运行
Windows Server 2008 R2 x64的服务器,带有4GB的RAM,可容纳大约2-3百万个文件,其中大部分是图像文件.

在一个星期的过程中,我注意到服务器上的应用程序由于内存不足而导致对磁盘的过度分页而导致爬行速度变慢,这会对当前在其上运行的所有服务产生连锁效应,导致主要问题性能问题.

在任务管理器中进行调查后,我注意到几乎所有4GB都在使用中,但是当您查看“进程”选项卡时,所有内存使用量的总和不会累加,最多只有1.5GB应该在使用中.

使用Google查找解决方案,似乎大多数RAM都用在“Metafile”中,它是文件系统上文件的NTFS信息缓存,因此系统不必再次向MFT查询信息.此缓存永远不会在任务管理器中清除或标记为“缓存”,或在Sysinternal的RamMap中标记为“待机”.

有a suggestion安装KB979149修复程序,但在尝试安装它时,它说“此更新不适用于您的计算机”.

到目前为止,我发现的唯一临时修复是:

>每隔1-3天使用来自Sysinternals的RAMmap到“清空系统工作集”,在任务管理器中将缓存标记为“待机”和“缓存”,以便其他应用程序可以使用RAM.
>重启机器,这是不受欢迎的,因为此服务器正在为公共网站提供服务.

目前我不得不每隔几天执行2.修复以防止它达到瓶颈水平.

之前:(使用800MB RAM – 其他应用程序无法使用此RAM)

之后:(800MB RAM标记为缓存 – 可用于其他应用程序)

所以我的问题是:是否存在任何方法来限制此元文件的RAM使用?

处理此问题的最佳方法是使用
SetSystemFileCacheSize API作为
MSKB976618 instructs
MS KB976618 used to instruct.

不要定期清除缓存

使用SetSystemFileCacheSize函数而不是定期清除缓存可以提高性能和稳定性.定期清除缓存将导致过多的元文件和其他信息从内存中清除,并且窗口必须从HDD重新读取所需信息到RAM中.每当您清除缓存时,这会在几秒钟内导致性能突然严重下降,随后性能会随着内存填充元文件数据而慢慢降低.

使用SetSystemFileCacheSize函数设置最小值和最大值,这将导致窗口将多余的旧元文件数据标记为正常缓存功能可根据当前资源需求和正常缓存优先级使用或丢弃的备用内存.这也允许比你设置的活动内存最多的元文件数据,如果windows在没有使用内存的情况下保留足够的可用内存,则将内存作为备用数据.这是保持系统性能特征始终良好的理想情况.

MS不支持第三方程序

如果您像我一样并且不想在生产服务器上运行来自某个未知第三方的二进制文件,那么您需要一个正式的MS工具或一些代码,您可以在这些服务器上运行之前检查它们.用于2008 R2的DynCache工具实际上不可能从M $获得而无需支付支持案例,坦率地说,基于2008年的代码,它似乎过于臃肿,因为Windows已经具有动态调整大小所需的内置逻辑缓存,它只需要知道您的系统适当的最大值.

解决所有上述问题

我写了一个适用于64位机器的powershell脚本.您需要以具有提升权限的管理员身份运行它.您应该可以在任何x64 Windows Vista / Server 2008上运行它,包括任意数量的RAM的10 / Server 2012 R2.您无需安装任何其他软件,因此可以使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",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,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",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,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]$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脚本并将其发布
https://stackoverflow.com/questions/5898843/c-sharp-get-system-file-cache-size/17875550#17875550

编辑:我还应该指出,您不应该多次从同一个PowerShell实例运行这两个脚本中的任何一个,否则您将收到已经进行了Add-Type调用的错误.

编辑:更新了SetSystemFileCacheSize脚本到版本1.1,为您计算适当的最大缓存值,并具有更好的状态输出布局.

编辑:现在我升级了我的Windows 7笔记本电脑,我可以告诉你该脚本在Windows 10中成功运行,但我还没有测试它是否仍然需要.但即使在移动虚拟机硬盘文件时,我的系统仍然稳定.

相关文章

发表回复

您的电子邮箱地址不会被公开。