1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Fix game stutter on Win 10 1703-1809

Discussion in 'Videocards - NVIDIA GeForce Drivers Section' started by Mott, Apr 3, 2018.

  1. EdKiefer

    EdKiefer Ancient Guru

    Messages:
    2,284
    Likes Received:
    176
    GPU:
    MSI 970 Gaming 4G
    I was just curious, and yes I don't think I am affected, that I can tell.
    Thanks for the break down.
     
  2. harkinsteven

    harkinsteven Ancient Guru

    Messages:
    2,896
    Likes Received:
    79
    GPU:
    RTX 2080 ti
    Please do.
     
  3. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    @Mott Btw, I found specialized cache related Win API function capable to clear the cache:
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa965240(v=vs.85).aspx

    So your PowerShell script can be greatly simplified:
    instead of
    Code:
    if (!Is64BitMode())
    {
    SYSTEM_CACHE_INFORMATION cacheInformation = new SYSTEM_CACHE_INFORMATION();
    cacheInformation.MinimumWorkingSet = uint.MaxValue;
    cacheInformation.MaximumWorkingSet = uint.MaxValue;
    SystemInfoLength = Marshal.SizeOf(cacheInformation);
    gcHandle = GCHandle.Alloc(cacheInformation, GCHandleType.Pinned);
    num1 = NtSetSystemInformation(SystemFileCacheInformation, gcHandle.AddrOfPinnedObject(), SystemInfoLength);
    gcHandle.Free();
    }
    else
    {
    SYSTEM_CACHE_INFORMATION_64_BIT information64Bit = new SYSTEM_CACHE_INFORMATION_64_BIT();
    information64Bit.MinimumWorkingSet = -1L;
    information64Bit.MaximumWorkingSet = -1L;
    SystemInfoLength = Marshal.SizeOf(information64Bit);
    gcHandle = GCHandle.Alloc(information64Bit, GCHandleType.Pinned);
    num1 = NtSetSystemInformation(SystemFileCacheInformation, gcHandle.AddrOfPinnedObject(), SystemInfoLength);
    gcHandle.Free();
    }
    
    where NtSetSystemInformation is:
    [DllImport("ntdll.dll")]
    public static extern UInt32 NtSetSystemInformation(int InfoClass, IntPtr Info, int Length);
    this
    Code:
    num1 = SetSystemFileCacheSize(IntPtr.Subtract(IntPtr.Zero,1), IntPtr.Subtract(IntPtr.Zero,1), 0);
    
    where SetSystemFileCacheSize is:
    [DllImport("Kernel32.dll", SetLastError = true)]
    static extern uint SetSystemFileCacheSize(IntPtr MinimumFileCacheSize, IntPtr MaximumFileCacheSize, UInt32 Flags);

    Plus you can drop definitions of SYSTEM_CACHE_INFORMATION and SYSTEM_CACHE_INFORMATION_64_BIT.

    PS Someone implemented command line utility with this API function
    https://www.softpedia.com/get/System/System-Miscellaneous/SetSystemFileCacheSize.shtml
    I don`t know whether developer implemented support for "-1" argument, but these values can be used instead - "4294967295" for x86, "18446744073709551615" for x64. You can check whether it clears the cache. And if it does then it can be used in your bat-file instead of calling the PowerShell.
     
    Last edited: Sep 25, 2018
    Mott likes this.
  4. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    OK then.
    (But mind you, @Dynarush_333, it will be C# code.)
     
    Last edited: Sep 25, 2018
    Dynarush_333 likes this.

  5. Mott

    Mott Master Guru

    Messages:
    822
    Likes Received:
    150
    GPU:
    MSI 1080 Ti GamingX
    @mbk1969 I greatly appreciate you going through the code and cleaning it up. I, however, cannot take credit for the code as not only did I not wrote it but I also don't know how to code. I read about it on the thread posted in the OP here and discussion surrounding it.

    Could you put together a new file with your edits and I will try and run them by the original creator of the script?

    Thanks for the input as always it is much appreciated!
     
  6. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    @Mott Here you go - simplified version with PowerShell
    <# : batch wrapper and schedule by AveYo, v2
    @Echo off &title FreeStandbyMemory

    set CLEAR_EVERY_MINUTES=5
    set CLEAR_WHEN_UNDER_MB=512

    if %1.==schedule. (goto schedule) else goto setup_schedule
    :need_admin_rights
    color 0c&echo. &echo PERMISSION DENIED! Right-click %~nx0 ^& Run as administrator &timeout /t 60 &color 0f&title %COMSPEC% &exit/b
    :setup_schedule
    reg query "HKEY_USERS\S-1-5-20\Environment" /v TEMP >nul 2>nul || goto need_admin_rights
    echo CLEAR_EVERY_MINUTES=%CLEAR_EVERY_MINUTES%
    echo CLEAR_WHEN_UNDER_MB=%CLEAR_WHEN_UNDER_MB%
    set "f0=%Windir%\FreeStandbyMemory.bat"
    if /i "%~f0"=="%f0%" (set "COPY2WINDIR=") else echo|set/p=%f0% &copy /y "%~f0" "%f0%" &set "COPY2WINDIR=yes"
    set "tn=FreeStandbyMemory" &set "mo=%CLEAR_EVERY_MINUTES%" &set "tr=cmd.exe /c call \"%f0%\" schedule"
    schtasks /Delete /TN "%tn%" /f
    schtasks /Create /RU "System" /sc MINUTE /MO %mo% /TN "%tn%" /TR "%tr%" /ST "12:00:00" /NP /F
    schtasks /Run /TN "%tn%"
    timeout /t -1
    exit/b
    :schedule
    for /f "delims=" %%# in ('wmic path win32_Operatingsystem get FreePhysicalMemory /VALUE ^|find "Free"') do set "%%#"
    set/a ClearWhenUnderKB=1024*%CLEAR_WHEN_UNDER_MB%
    if %FreePhysicalMemory% GEQ %ClearWhenUnderKB% exit &rem v2: use wmic as it's faster to check freemem than launching ps instance
    type "%~f0" | powershell -c - &exit
    #>

    # PowerShell wrapper script for clear StandBy memory without RAMMap
    # https://gallery.technet.microsoft.com/scriptcenter/c-PowerShell-wrapper-6465e028
    # by Alexander Korotkov

    $Source = @"
    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Security.Principal;

    namespace ClearStandbyList
    {
    public class Program
    {
    const int SE_PRIVILEGE_ENABLED = 2;
    const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege";
    const string SE_PROFILE_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege";
    const int SystemFileCacheInformation = 0x0015;
    const int SystemMemoryListInformation = 0x0050;
    const int MemoryPurgeStandbyList = 4;
    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
    [DllImport("ntdll.dll", SetLastError = true)]
    public static extern UInt32 NtSetSystemInformation(int InfoClass, IntPtr Info, int Length);
    [DllImport("Kernel32.dll", SetLastError = true)]
    static extern UInt32 SetSystemFileCacheSize(IntPtr MinimumFileCacheSize, IntPtr MaximumFileCacheSize, UInt32 Flags);

    static void Main(string[] args)
    {
    ClearFileSystemCache(true);
    }
    public static void ClearFileSystemCache(bool ClearStandbyCache)
    {
    try
    {
    if (SetIncreasePrivilege(SE_INCREASE_QUOTA_NAME))
    {
    uint num1 = SetSystemFileCacheSize(IntPtr.Subtract(IntPtr.Zero,1), IntPtr.Subtract(IntPtr.Zero,1), 0);
    if (num1 == 0)
    throw new Exception("SetSystemFileCacheSize() error: ", new Win32Exception(Marshal.GetLastWin32Error()));
    }
    if (ClearStandbyCache && SetIncreasePrivilege(SE_PROFILE_SINGLE_PROCESS_NAME))
    {

    int SystemInfoLength = Marshal.SizeOf(MemoryPurgeStandbyList);
    GCHandle gcHandle = GCHandle.Alloc(MemoryPurgeStandbyList, GCHandleType.Pinned);
    uint num2 = NtSetSystemInformation(SystemMemoryListInformation, gcHandle.AddrOfPinnedObject(), SystemInfoLength);
    gcHandle.Free();
    if (num2 != 0)
    throw new Exception("NtSetSystemInformation(SYSTEMMEMORYLISTINFORMATION) error: ", new Win32Exception(Marshal.GetLastWin32Error()));
    }
    }
    catch (Exception ex)
    {
    Console.Write(ex.ToString());
    }
    }
    private static bool SetIncreasePrivilege(string privilegeName)
    {
    using (WindowsIdentity current = WindowsIdentity.GetCurrent(TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges))
    {
    TokPriv1Luid newst;
    newst.Count = 1;
    newst.Luid = 0L;
    newst.Attr = SE_PRIVILEGE_ENABLED;
    if (!LookupPrivilegeValue(null, privilegeName, ref newst.Luid))
    throw new Exception("Error in LookupPrivilegeValue: ", new Win32Exception(Marshal.GetLastWin32Error()));
    int num = AdjustTokenPrivileges(current.Token, false, ref newst, 0, IntPtr.Zero, IntPtr.Zero) ? 1 : 0;
    if (num == 0)
    throw new Exception("Error in AdjustTokenPrivileges: ", new Win32Exception(Marshal.GetLastWin32Error()));
    return num != 0;
    }
    }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid
    {
    public int Count;
    public long Luid;
    public int Attr;
    }
    }
    "@

    Add-Type -TypeDefinition $Source -Language CSharp

    [ClearStandbyList.Program]::ClearFileSystemCache($true)
    #
    Update: There was a bug with this ^ script - fixed.


    While we are at testing, can you test this version without the cleaning of file cache? It seems to me that cleaning both - file cache and standby list - is not necessary.
    <# : batch wrapper and schedule by AveYo, v2
    @Echo off &title FreeStandbyMemory

    set CLEAR_EVERY_MINUTES=5
    set CLEAR_WHEN_UNDER_MB=512

    if %1.==schedule. (goto schedule) else goto setup_schedule
    :need_admin_rights
    color 0c&echo. &echo PERMISSION DENIED! Right-click %~nx0 ^& Run as administrator &timeout /t 60 &color 0f&title %COMSPEC% &exit/b
    :setup_schedule
    reg query "HKEY_USERS\S-1-5-20\Environment" /v TEMP >nul 2>nul || goto need_admin_rights
    echo CLEAR_EVERY_MINUTES=%CLEAR_EVERY_MINUTES%
    echo CLEAR_WHEN_UNDER_MB=%CLEAR_WHEN_UNDER_MB%
    set "f0=%Windir%\FreeStandbyMemory.bat"
    if /i "%~f0"=="%f0%" (set "COPY2WINDIR=") else echo|set/p=%f0% &copy /y "%~f0" "%f0%" &set "COPY2WINDIR=yes"
    set "tn=FreeStandbyMemory" &set "mo=%CLEAR_EVERY_MINUTES%" &set "tr=cmd.exe /c call \"%f0%\" schedule"
    schtasks /Delete /TN "%tn%" /f
    schtasks /Create /RU "System" /sc MINUTE /MO %mo% /TN "%tn%" /TR "%tr%" /ST "12:00:00" /NP /F
    schtasks /Run /TN "%tn%"
    timeout /t -1
    exit/b
    :schedule
    for /f "delims=" %%# in ('wmic path win32_Operatingsystem get FreePhysicalMemory /VALUE ^|find "Free"') do set "%%#"
    set/a ClearWhenUnderKB=1024*%CLEAR_WHEN_UNDER_MB%
    if %FreePhysicalMemory% GEQ %ClearWhenUnderKB% exit &rem v2: use wmic as it's faster to check freemem than launching ps instance
    type "%~f0" | powershell -c - &exit
    #>

    # PowerShell wrapper script for clear StandBy memory without RAMMap
    # https://gallery.technet.microsoft.com/scriptcenter/c-PowerShell-wrapper-6465e028
    # by Alexander Korotkov

    $Source = @"
    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Security.Principal;

    namespace ClearStandbyList
    {
    public class Program
    {
    const int SE_PRIVILEGE_ENABLED = 2;
    const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege";
    const string SE_PROFILE_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege";
    const int SystemFileCacheInformation = 0x0015;
    const int SystemMemoryListInformation = 0x0050;
    const int MemoryPurgeStandbyList = 4;
    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
    [DllImport("ntdll.dll", SetLastError = true)]
    public static extern UInt32 NtSetSystemInformation(int InfoClass, IntPtr Info, int Length);
    [DllImport("Kernel32.dll", SetLastError = true)]
    static extern UInt32 SetSystemFileCacheSize(IntPtr MinimumFileCacheSize, IntPtr MaximumFileCacheSize, UInt32 Flags);

    static void Main(string[] args)
    {
    ClearFileSystemCache(true);
    }
    public static void ClearFileSystemCache(bool ClearStandbyCache)
    {
    try
    {
    if (ClearStandbyCache && SetIncreasePrivilege(SE_PROFILE_SINGLE_PROCESS_NAME))
    {

    int SystemInfoLength = Marshal.SizeOf(MemoryPurgeStandbyList);
    GCHandle gcHandle = GCHandle.Alloc(MemoryPurgeStandbyList, GCHandleType.Pinned);
    uint num2 = NtSetSystemInformation(SystemMemoryListInformation, gcHandle.AddrOfPinnedObject(), SystemInfoLength);
    gcHandle.Free();
    if (num2 != 0)
    throw new Exception("NtSetSystemInformation(SYSTEMMEMORYLISTINFORMATION) error: ", new Win32Exception(Marshal.GetLastWin32Error()));
    }
    }
    catch (Exception ex)
    {
    Console.Write(ex.ToString());
    }
    }
    private static bool SetIncreasePrivilege(string privilegeName)
    {
    using (WindowsIdentity current = WindowsIdentity.GetCurrent(TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges))
    {
    TokPriv1Luid newst;
    newst.Count = 1;
    newst.Luid = 0L;
    newst.Attr = SE_PRIVILEGE_ENABLED;
    if (!LookupPrivilegeValue(null, privilegeName, ref newst.Luid))
    throw new Exception("Error in LookupPrivilegeValue: ", new Win32Exception(Marshal.GetLastWin32Error()));
    int num = AdjustTokenPrivileges(current.Token, false, ref newst, 0, IntPtr.Zero, IntPtr.Zero) ? 1 : 0;
    if (num == 0)
    throw new Exception("Error in AdjustTokenPrivileges: ", new Win32Exception(Marshal.GetLastWin32Error()));
    return num != 0;
    }
    }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid
    {
    public int Count;
    public long Luid;
    public int Attr;
    }
    }
    "@

    Add-Type -TypeDefinition $Source -Language CSharp

    [ClearStandbyList.Program]::ClearFileSystemCache($true)
    #
     
    Last edited: Sep 25, 2018
    Mott likes this.
  7. Mott

    Mott Master Guru

    Messages:
    822
    Likes Received:
    150
    GPU:
    MSI 1080 Ti GamingX
    Great! Thanks a lot. I am running it by the original creatoor of the script to see what he has to say and I will try to test your script if I can get some gaming in the next few days.
     
  8. Mott

    Mott Master Guru

    Messages:
    822
    Likes Received:
    150
    GPU:
    MSI 1080 Ti GamingX
    @mbk1969 here is the original author's response to your proposed simplified version:

    "No offense, but that's not a cleaned up version - that's a butchered version that does not work :)
    What's the point on "cleaning up" a 6.6KB script towards a 4.6KB (incomplete), when both take 8KB on disk :D
    And there's no meaningful speed to be gained as long as simply opening a ps instance takes longer.
    The main reason I decided to go with the script as-is was for maintainability. Second one was trust.
    If it ain't broken, don't fix it.
    But if you must, I suggest running the stand-alone ps content inside powershell (admin) directly to see whatever errors are reported"

    I think it is safe to say we should just stick with their script and be happy with it.
     
  9. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    Which one version of bat-file he is talking about - first or second? I have not said "cleaned up version". I have said "simplified version". If he sees no difference then I can say he is not 'paranoid' programmer. Anyway, I will finish system service because no one will convince me that bat-file plus powershell script works better then system service. And since I will deploy service in source file (along with powershell script to build service binary and configure it), trust should not be the issue.

    Can you test the second version of bat-file with only standby cleaning anyway? I suspect that such cleaning can be enough for the purposes of workaround discussed here.
     
  10. Mott

    Mott Master Guru

    Messages:
    822
    Likes Received:
    150
    GPU:
    MSI 1080 Ti GamingX
    Sorry for misrepresenting you there with the terminology. I will definitely let you know when I get a chance to try out your second one. I showed the first one to the person who posted the script. I would suggest that you go to the specific reply in the Reddit post which I referenced and open a dialogue with the person who posted the script as I think you two could come up with something really good for everyone.
     
    Last edited: Sep 26, 2018

  11. mootyful

    mootyful Member

    Messages:
    27
    Likes Received:
    3
    GPU:
    GTX 760 Gigabyte
    Mott likes this.
  12. norton

    norton Member Guru

    Messages:
    181
    Likes Received:
    45
    GPU:
    GTX970 G1 Gaming
    kaspersky blocked the script from running even if i copy the code myself i know it may be a false positive
     
  13. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    Of course not. Author wanted to achieve the world domination with this script.
     
  14. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    I found a way to run task on alert from performance counter data
    https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/logman-create-alert

    For example
    logman create alert mem_alert -th "\Memory\Available MBytes<500" -tn "ClearStandbyList" -si 05:00
    where:
    -th "\Memory\Available MBytes<500" specifies counter and treshold;
    -tn "ClearStandbyList" specifies the name of the task in Task scheduler; for example task can execute powershell with the script of Alexander Korotkov (in OP);
    -si 05:00 specifies the sample interval (5 minutes) for performance counter data collectors.

    I will experiment with this to create bat-file for creating schedule task and perf. counter alert. In my opinion this is more sophisticated way.
     
    Last edited: Sep 26, 2018
    disq likes this.
  15. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    .exe - RAMMap.exe ? These scripts - ???

    You can test the PowerShell part: download the script - https://gallery.technet.microsoft.com/scriptcenter/c-PowerShell-wrapper-6465e028#content
    launch powershell.exe as administrator and execute script there.
     

  16. isamu99

    isamu99 Member

    Messages:
    42
    Likes Received:
    0
    Thank you very much Matt for posting this fix. I will run it before I do I have a dumb question. After creating the batch file, where on my PC exactly should I place it? Or does it not matter?
     
  17. windrunnerxj

    windrunnerxj Master Guru

    Messages:
    203
    Likes Received:
    9
    GPU:
    MSI Gaming 1060 6G
    I think you can delete it after you run it once.
    It should create another bat file in your Windows directory (FreeStandbyMemory.bat) and task scheduler will use that file afterwards. You can check if you have this bat in your Windows folder after you run it.
     
  18. Mott

    Mott Master Guru

    Messages:
    822
    Likes Received:
    150
    GPU:
    MSI 1080 Ti GamingX
    This question has already been answered but I will again. It sets up a task in your events manager which will run indefinitely. Once you have run the batch file you should back it up in case you reinstall windows and want to use it again or just delete it and download it from my link if you ever need it. The task is setup by the batch file and the file is no longer needed as the task is created and part of your system!
     
  19. mbk1969

    mbk1969 Ancient Guru

    Messages:
    7,681
    Likes Received:
    4,274
    GPU:
    GeForce GTX 1070
    Here is alternative way with scripts.

    Create folder "PurgeMemCache" and paste these files there:

    - setup.bat
    Code:
    @echo off
    rem format for CLEAR_EVERY_MINUTES is MM:SS. if CLEAR_EVERY_MINUTES is less then 10 minutes use leading zero - 01:00, 02:00, 03:00, ..., 09:00.
    set CLEAR_EVERY_MINUTES=10:00
    set CLEAR_WHEN_UNDER_MB=512
    cd %~dp0
    echo Compiling console application...
    c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe -target:exe -subsystemversion:6.01 PurgeMemCache.cs > nul || exit /b 1)
    echo.
    echo Creating task with console application...
    Schtasks.exe /Create /Tn PurgeStandbyList /Ru SYSTEM /Sc ONIDLE /I 999 /Tr "%~dp0PurgeMemCache.exe" > nul || exit /b 2)
    echo.
    echo Creating performance counter alert and task for starting this alert on every logon...
    logman.exe create alert LowMemAlert -th "\Memory\Available MBytes<%CLEAR_WHEN_UNDER_MB%" -tn "PurgeStandbyList" -si %CLEAR_EVERY_MINUTES% -m start stop > nul || exit /b 3
    Schtasks.exe /Create /Tn StartLowMemAlert /Ru SYSTEM /Sc ONLOGON /Tr "logman start LowMemAlert" > nul || exit /b 4
    echo.
    echo Starting performance counter alert...
    logman.exe start LowMemAlert > nul || exit /b 5
    echo.
    echo Success!
    exit /b
    

    - cleanup.bat
    Code:
    @echo off
    echo Stopping and deleting perfomance counter alert...
    logman.exe stop LowMemAlert
    logman.exe delete LowMemAlert
    echo.
    echo Stopping and deleting tasks...
    Schtasks.exe /End /Tn PurgeStandbyList
    Schtasks.exe /Delete /Tn PurgeStandbyList /F
    Schtasks.exe /End /Tn StartLowMemAlert
    Schtasks.exe /Delete /Tn StartLowMemAlert /F
    echo.
    echo Deleting console application...
    cd %~dp0
    del /F /Q PurgeMemCache.exe
    

    - PurgeMemCache.cs
    Code:
    using System;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    
    namespace PurgeMemCache
    {
        class Program
        {
            [System.Security.SuppressUnmanagedCodeSecurity]
            [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions]
            static int Main(string[] args)
            {
                try
                {
                    using (var current = WindowsIdentity.GetCurrent(TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges))
                    {
                        TokPriv1Luid newst;
                        newst.Count = 1; newst.Luid = 0L; newst.Attr = 2;// SE_PRIVILEGE_ENABLED;
                        if (!LookupPrivilegeValue(null, "SeProfileSingleProcessPrivilege", ref newst.Luid))
                        {
                            Console.Error.Write("Error in LookupPrivilegeValue: {0}", Marshal.GetLastWin32Error());
                            return 1;
                        }
                        if (!AdjustTokenPrivileges(current.Token, false, ref newst, 0, IntPtr.Zero, IntPtr.Zero))
                        {
                            Console.Error.Write("Error in AdjustTokenPrivileges: {0}", Marshal.GetLastWin32Error());
                            return 2;
                        }
    
                        int SystemMemoryListInformation = 0x0050;
                        int MemoryPurgeStandbyList = 4;
                        uint res = NtSetSystemInformation(SystemMemoryListInformation, ref MemoryPurgeStandbyList, Marshal.SizeOf(MemoryPurgeStandbyList));
                        if (res != 0)
                        {
                            Console.Error.Write("Error in NtSetSystemInformation: {0}", Marshal.GetLastWin32Error());
                            return 3;
                        }
                    }
                    return 0;
                }
                catch(Exception ex)
                {
                    Console.Error.Write("Unexpected error:\n{0}", ex.ToString());
                    return 4;
                }
            }
    
            [DllImport("advapi32.dll", SetLastError = true)]
            static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
    
            [DllImport("advapi32.dll", SetLastError = true)]
            static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
    
            [DllImport("ntdll.dll", SetLastError = true)]
            static extern UInt32 NtSetSystemInformation(int InfoClass, ref int Info, int Length);
    
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            struct TokPriv1Luid
            {
                public int Count;
                public long Luid;
                public int Attr;
            }
        }
    }
    

    setup.but should do these steps:
    - build C# source file into console application (with C# compiler in .Net Framework folder) "PurgeMemCache.exe"
    - create task "PurgeStandbyList" with this console application
    - create performance counter ("\Memory\Available MBytes<%CLEAR_WHEN_UNDER_MB%") alert "LowMemAlert" with check for every "%CLEAR_EVERY_MINUTES%" minutes, and with call of task "PurgeStandbyList" (in case the check result is true)
    - create task "StartLowMemAlert" which should start the performance counter alert "LowMemAlert" at every logon
    - start the performance counter alert "LowMemAlert"
    You can change the values CLEAR_EVERY_MINUTES - performance counter sampling interval, and CLEAR_WHEN_UNDER_MB - the treshold for calling the purge of standby list.

    cleanup.bat should do these steps:
    - stop and delete the performance counter alert "LowMemAlert"
    - stop and delete task "PurgeStandbyList"
    - stop and delete task "StartLowMemAlert"
    - delete console application

    PurgeMemCache.cs file is just reworked code of original PowerShell script published by Alexander Korotkov. I removed purging of file cache because my tests showed that purging the standby list is enough for getting back free memory. In case of error application should return code of error: 1, 2, 3 or 4. And of course you can execute (as administrator) console application built from this source file any time you want.

    I have tested all this at work on Win8.1. I will test also at home on Win10. Update: tested is at home on Win10 - all is working.



    PS Meanwhile version of standby list purge tool in the form of system service is almost done. Should test it and will publish soon.
     
    Last edited: Sep 30, 2018
    Dynarush_333 and disq like this.
  20. SpookySkeleton

    SpookySkeleton Member Guru

    Messages:
    127
    Likes Received:
    19
    GPU:
    GTX 1080
    for me still the system gets laggy and have sttutering after 16+ hours of uptime. I hope ms fix this, it's really annoying to restart pc everytime just to play a game o start a new project. I don't really want to go back to win 8,1 or have to switch between linux or windows everytime..
     

Share This Page