Skip to content

Instantly share code, notes, and snippets.

@AveYo
Last active November 23, 2023 21:16
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save AveYo/2cee207bdb67525e34c45dff76be0b16 to your computer and use it in GitHub Desktop.
Save AveYo/2cee207bdb67525e34c45dff76be0b16 to your computer and use it in GitHub Desktop.
FreeStandbyMemory.bat - ninja edits at https://pastebin.com/Kj36ug5h
/* 2>nul || title FreeStandbyMemory.bat by AveYo v2019.06.01
@echo off|| csc compiling snippet, advanced schedule, builtin add_remove - UPDATE: reliable free memory detection
set/a CLEAR_EVERY_MINUTES=1
set/a CLEAR_WHEN_UNDER_MB=512
set/a CLEAR_SYSTEMCACHEWS=0
:: check_admin_rights
reg query "HKEY_USERS\S-1-5-20\Environment" /v TEMP >nul 2>nul || (
color 0e & echo. & echo PERMISSION DENIED! Right-click %~nx0 ^& Run as administrator
timeout /t -1 & color 0f & title %COMSPEC% & exit/b
)
:: add_remove whenever script is run again
schtasks /query /tn FreeStandbyMemory >nul 2>nul && (
echo.
schtasks /Delete /TN "FreeStandbyMemory" /f 2>nul
reg delete HKLM\Software\AveYo /v FreeStandbyMemory /f 2>nul
del /f /q "%Windir%\FreeStandbyMemory.exe" 2>nul
color 0b &echo. &echo REMOVED! Run script again to recompile and add schedule!
timeout /t -1 &color 0f &title %COMSPEC% &exit/b
)
:: compile c# snippet
pushd %~dp0
del /f /q FreeStandbyMemory.exe >nul 2>nul
for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d /o:-n "%Windir%\Microsoft.NET\*csc.exe"') do set "csc="%%v""
%csc% /out:FreeStandbyMemory.exe /target:winexe /platform:anycpu /optimize /nologo "%~f0"
if not exist FreeStandbyMemory.exe echo ERROR! Failed compiling c# snippet & timeout /t -1 & exit /b
echo|set/p=FreeStandbyMemory.exe &copy /y FreeStandbyMemory.exe "%Windir%\FreeStandbyMemory.exe" &set "OUTDIR=%Windir%"
if not exist "%Windir%\FreeStandbyMemory.exe" echo WARNING! Cannot copy FreeStandbyMemory.exe to %Windir%\ &set "OUTDIR=%CD%"
:: setup advanced schedule - can afford higher priority after switching from wmi to winapi
set "task_run=%OUTDIR%\FreeStandbyMemory.exe %CLEAR_WHEN_UNDER_MB% %CLEAR_SYSTEMCACHEWS%"
set "schedule=/Create /RU "System" /NP /RL HIGHEST /F /SD "01/01/2001" /ST "01:00:00" "
schtasks %schedule% /SC MINUTE /MO %CLEAR_EVERY_MINUTES% /TN "FreeStandbyMemory" /TR "%task_run%"
set "sset=$s=New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -Priority 1 -StartWhenAvailable;"
set "stopexisting=$s.CimInstanceProperties['MultipleInstances'].Value=3;"
powershell -noprofile -c "%sset% %stopexisting% $null=Set-ScheduledTask -TaskName FreeStandbyMemory -Settings $s"
:: trigger task, force a manual clear and finish setup
schtasks /Run /TN "FreeStandbyMemory"
echo.
echo Clearing StandbyMemory every %CLEAR_EVERY_MINUTES% minutes ONLY if free memory goes under %CLEAR_WHEN_UNDER_MB% MB
echo Can force a clear manually from Command Prompt (Admin) by entering: freestandbymemory
echo.
echo ADDED! Run "%~nx0" again to remove compiled snippet and schedule!
timeout /t -1
exit /b
:: Based on idea from "PowerShell wrapper script for clear StandBy memory without RAMMap" by Alexander Korotkov
:: Implemented SetSystemFileCacheSize and NtSetSystemInformation suggestions by Maks.K
:: Using RtlAdjustPrivilege, GetPerformanceInfo, force clear if no args, stripped output, sanitized by AveYo
*/
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Reflection;
[assembly:AssemblyTitle("FreeStandbyMemory")]
[assembly:AssemblyCopyrightAttribute("AveYo")]
[assembly:AssemblyVersionAttribute("2019.06.01")]
namespace FreeStandbyMemory
{
class Program
{
static bool retv = false;
static int MemoryPurgeStandbyList = 0x0004;
const int SystemFileCacheInformation = 0x0015;
const int SystemMemoryListInformation = 0x0050;
const int SE_INCREASE_QUOTA_PRIVILEGE = 0x00000005;
const int SE_PROF_SINGLE_PROCESS_PRIVILEGE = 0x0000000d;
[StructLayout(LayoutKind.Sequential)]
private class PERFINFO
{
public int cb;
public IntPtr CommitTotal;
public IntPtr CommitLimit;
public IntPtr CommitPeak;
public IntPtr PhysicalTotal;
public IntPtr PhysicalAvailable;
public IntPtr SystemCache;
public IntPtr KernelTotal;
public IntPtr KernelPaged;
public IntPtr KernelNonpaged;
public IntPtr PageSize;
public int HandleCount;
public int ProcessCount;
public int ThreadCount;
public PERFINFO()
{
this.cb = (int)Marshal.SizeOf(typeof(PERFINFO));
}
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport( "psapi.dll", CharSet = CharSet.Auto, SetLastError = true )]
static extern bool GetPerformanceInfo([In, Out] PERFINFO pi);
[DllImport("psapi.dll")]
static extern bool EmptyWorkingSet(IntPtr hwProc);
[DllImport("kernel32.dll")]
static extern bool SetSystemFileCacheSize(IntPtr MinimumFileCacheSize, IntPtr MaximumFileCacheSize, int Flags);
[DllImport("ntdll.dll")]
static extern IntPtr RtlAdjustPrivilege(int Privilege, bool Enable, bool CurrentThread, out bool RetValue);
[DllImport("ntdll.dll")]
static extern IntPtr NtSetSystemInformation(int InfoClass, out int Info, int Length);
static void Main(string[] args)
{
int target = (args.Length == 0) ? Int32.MaxValue : Convert.ToInt32(args[0]);
bool systemcachews = (args.Length == 0 || args.Length >= 2 && args[1] == "1");
Int64 free = 0;
PERFINFO pi = new PERFINFO();
if (GetPerformanceInfo(pi))
{
Int64 avail = pi.PhysicalAvailable.ToInt64();
Int64 cache = pi.SystemCache.ToInt64();
Int64 page = pi.PageSize.ToInt64();
free = ( (avail > cache) ? avail - cache : cache - avail ) * page >> 20;
/* To debug, change csc /target:winexe to /target:exe and uncomment the Console.WriteLine's */
////Console.WriteLine("Total: {0,5}MB", pi.PhysicalTotal.ToInt64() * page >> 20);
////Console.WriteLine("Avail: {0,5}MB", pi.PhysicalAvailable.ToInt64() * page >> 20);
////Console.WriteLine("Cache: {0,5}MB", pi.SystemCache.ToInt64() * page >> 20);
////Console.WriteLine("Free: {0,5}MB", free);
}
if (free > target) return;
////Console.WriteLine("Target:{0,5}MB - CLEARING!", target);
RtlAdjustPrivilege(SE_INCREASE_QUOTA_PRIVILEGE, true, false, out retv);
RtlAdjustPrivilege(SE_PROF_SINGLE_PROCESS_PRIVILEGE, true, false, out retv);
NtSetSystemInformation(SystemMemoryListInformation, out MemoryPurgeStandbyList, Marshal.SizeOf(MemoryPurgeStandbyList));
if (systemcachews) {
SetSystemFileCacheSize(new IntPtr(-1), new IntPtr(-1), 0);
Process[] processlist = Process.GetProcesses(); // Also free system processes working sets:
foreach(Process p in processlist) if (p.SessionId == 0) try { EmptyWorkingSet(p.Handle); } catch (Exception) {}
}
}
}
}
/*_*/
* text=auto
* eol=crlf
@samkatakouzinos
Copy link

Is CLEAR_SYSTEMCACHEWS a boolean value of 0 or 1?

@AveYo
Copy link
Author

AveYo commented Aug 1, 2019

int target = (args.Length == 0) ? Int32.MaxValue : Convert.ToInt32(args[0]);
bool systemcachews = (args.Length == 0 || args.Length >= 2 && args[1] == "1");

Calling without arguments: FreeStandbyMemory.exe
~ assumes you want a forced clear, so it sets target=MaxValue (more than your memory size) and systemcachews=true
Calling with only one argument: FreeStandbyMemory.exe 1024
~ assumes it's the CLEAR_WHEN_UNDER_MB parameter, so it sets target=1024 and systemcachews=false
Calling with two arguments: FreeStandbyMemory.exe 512 1
~ assumes first is the CLEAR_WHEN_UNDER_MB parameter, so it sets target=512
~ assumes second is the CLEAR_SYSTEMCACHEWS parameter, and only if it's "1" (as string) then sets systemcachews=true
otherwise sets systemcachews=false

@samkatakouzinos
Copy link

Thank you.

@samkatakouzinos
Copy link

Problem: Scheduled tasks Action with added arguments doesn't perform (eg 4096 0).
Note: Scheduled task Action with no added arguments does perform.
Running Windows 10 Pro 1903 18362.267

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment