SHOW:
|
|
- or go back to the newest paste.
1 | /* 2>nul || title FreeStandbyMemory.bat by AveYo v2019.06.01 | |
2 | @echo off|| csc compiling snippet, advanced schedule, builtin add_remove - UPDATE: reliable free memory detection | |
3 | ||
4 | set/a CLEAR_EVERY_MINUTES=1 | |
5 | set/a CLEAR_WHEN_UNDER_MB=512 | |
6 | set/a CLEAR_SYSTEMCACHEWS=0 | |
7 | ||
8 | :: check_admin_rights | |
9 | reg query "HKEY_USERS\S-1-5-20\Environment" /v TEMP >nul 2>nul || ( | |
10 | color 0e & echo. & echo PERMISSION DENIED! Right-click %~nx0 ^& Run as administrator | |
11 | timeout /t -1 & color 0f & title %COMSPEC% & exit/b | |
12 | ) | |
13 | ||
14 | :: add_remove whenever script is run again | |
15 | schtasks /query /tn FreeStandbyMemory >nul 2>nul && ( | |
16 | echo. | |
17 | schtasks /Delete /TN "FreeStandbyMemory" /f 2>nul | |
18 | reg delete HKLM\Software\AveYo /v FreeStandbyMemory /f 2>nul | |
19 | del /f /q "%Windir%\FreeStandbyMemory.exe" 2>nul | |
20 | color 0b &echo. &echo REMOVED! Run script again to recompile and add schedule! | |
21 | timeout /t -1 &color 0f &title %COMSPEC% &exit/b | |
22 | ) | |
23 | ||
24 | :: compile c# snippet | |
25 | pushd %~dp0 | |
26 | del /f /q FreeStandbyMemory.exe >nul 2>nul | |
27 | for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d /o:-n "%Windir%\Microsoft.NET\*csc.exe"') do set "csc="%%v"" | |
28 | %csc% /out:FreeStandbyMemory.exe /target:winexe /platform:anycpu /optimize /nologo "%~f0" | |
29 | if not exist FreeStandbyMemory.exe echo ERROR! Failed compiling c# snippet & timeout /t -1 & exit /b | |
30 | echo|set/p=FreeStandbyMemory.exe © /y FreeStandbyMemory.exe "%Windir%\FreeStandbyMemory.exe" &set "OUTDIR=%Windir%" | |
31 | if not exist "%Windir%\FreeStandbyMemory.exe" echo WARNING! Cannot copy FreeStandbyMemory.exe to %Windir%\ &set "OUTDIR=%CD%" | |
32 | ||
33 | :: setup advanced schedule - can afford higher priority after switching from wmi to winapi | |
34 | set "task_run=%OUTDIR%\FreeStandbyMemory.exe %CLEAR_WHEN_UNDER_MB% %CLEAR_SYSTEMCACHEWS%" | |
35 | set "schedule=/Create /RU "System" /NP /RL HIGHEST /F /SD "01/01/2001" /ST "01:00:00" " | |
36 | schtasks %schedule% /SC MINUTE /MO %CLEAR_EVERY_MINUTES% /TN "FreeStandbyMemory" /TR "%task_run%" | |
37 | set "sset=$s=New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -Priority 1 -StartWhenAvailable;" | |
38 | set "stopexisting=$s.CimInstanceProperties['MultipleInstances'].Value=3;" | |
39 | powershell -noprofile -c "%sset% %stopexisting% $null=Set-ScheduledTask -TaskName FreeStandbyMemory -Settings $s" | |
40 | ||
41 | :: trigger task, force a manual clear and finish setup | |
42 | schtasks /Run /TN "FreeStandbyMemory" | |
43 | echo. | |
44 | echo Clearing StandbyMemory every %CLEAR_EVERY_MINUTES% minutes ONLY if free memory goes under %CLEAR_WHEN_UNDER_MB% MB | |
45 | echo Can force a clear manually from Command Prompt (Admin) by entering: freestandbymemory | |
46 | echo. | |
47 | echo ADDED! Run "%~nx0" again to remove compiled snippet and schedule! | |
48 | timeout /t -1 | |
49 | exit /b | |
50 | ||
51 | :: Based on idea from "PowerShell wrapper script for clear StandBy memory without RAMMap" by Alexander Korotkov | |
52 | :: Implemented SetSystemFileCacheSize and NtSetSystemInformation suggestions by Maks.K | |
53 | :: Using RtlAdjustPrivilege, GetPerformanceInfo, force clear if no args, stripped output, sanitized by AveYo | |
54 | */ | |
55 | using System; | |
56 | using System.Diagnostics; | |
57 | using System.Runtime.InteropServices; | |
58 | using System.Reflection; | |
59 | ||
60 | [assembly:AssemblyTitle("FreeStandbyMemory")] | |
61 | [assembly:AssemblyCopyrightAttribute("AveYo")] | |
62 | [assembly:AssemblyVersionAttribute("2019.06.01")] | |
63 | ||
64 | namespace FreeStandbyMemory | |
65 | { | |
66 | class Program | |
67 | { | |
68 | static bool retv = false; | |
69 | static int MemoryPurgeStandbyList = 0x0004; | |
70 | const int SystemFileCacheInformation = 0x0015; | |
71 | const int SystemMemoryListInformation = 0x0050; | |
72 | const int SE_INCREASE_QUOTA_PRIVILEGE = 0x00000005; | |
73 | const int SE_PROF_SINGLE_PROCESS_PRIVILEGE = 0x0000000d; | |
74 | [StructLayout(LayoutKind.Sequential)] | |
75 | private class PERFINFO | |
76 | { | |
77 | public int cb; | |
78 | public IntPtr CommitTotal; | |
79 | public IntPtr CommitLimit; | |
80 | public IntPtr CommitPeak; | |
81 | public IntPtr PhysicalTotal; | |
82 | public IntPtr PhysicalAvailable; | |
83 | public IntPtr SystemCache; | |
84 | public IntPtr KernelTotal; | |
85 | public IntPtr KernelPaged; | |
86 | public IntPtr KernelNonpaged; | |
87 | public IntPtr PageSize; | |
88 | public int HandleCount; | |
89 | public int ProcessCount; | |
90 | public int ThreadCount; | |
91 | public PERFINFO() | |
92 | { | |
93 | this.cb = (int)Marshal.SizeOf(typeof(PERFINFO)); | |
94 | } | |
95 | } | |
96 | [return: MarshalAs(UnmanagedType.Bool)] | |
97 | [DllImport( "psapi.dll", CharSet = CharSet.Auto, SetLastError = true )] | |
98 | static extern bool GetPerformanceInfo([In, Out] PERFINFO pi); | |
99 | [DllImport("psapi.dll")] | |
100 | static extern bool EmptyWorkingSet(IntPtr hwProc); | |
101 | [DllImport("kernel32.dll")] | |
102 | static extern bool SetSystemFileCacheSize(IntPtr MinimumFileCacheSize, IntPtr MaximumFileCacheSize, int Flags); | |
103 | [DllImport("ntdll.dll")] | |
104 | static extern IntPtr RtlAdjustPrivilege(int Privilege, bool Enable, bool CurrentThread, out bool RetValue); | |
105 | [DllImport("ntdll.dll")] | |
106 | static extern IntPtr NtSetSystemInformation(int InfoClass, out int Info, int Length); | |
107 | ||
108 | static void Main(string[] args) | |
109 | { | |
110 | int target = (args.Length == 0) ? Int32.MaxValue : Convert.ToInt32(args[0]); | |
111 | bool systemcachews = (args.Length == 0 || args.Length >= 2 && args[1] == "1"); | |
112 | Int64 free = 0; | |
113 | PERFINFO pi = new PERFINFO(); | |
114 | if (GetPerformanceInfo(pi)) | |
115 | { | |
116 | Int64 avail = pi.PhysicalAvailable.ToInt64(); | |
117 | Int64 cache = pi.SystemCache.ToInt64(); | |
118 | Int64 page = pi.PageSize.ToInt64(); | |
119 | free = ( (avail > cache) ? avail - cache : cache - avail ) * page >> 20; | |
120 | /* To debug, change csc /target:winexe to /target:exe and uncomment the Console.WriteLine's */ | |
121 | ////Console.WriteLine("Total: {0,5}MB", pi.PhysicalTotal.ToInt64() * page >> 20); | |
122 | ////Console.WriteLine("Avail: {0,5}MB", pi.PhysicalAvailable.ToInt64() * page >> 20); | |
123 | ////Console.WriteLine("Cache: {0,5}MB", pi.SystemCache.ToInt64() * page >> 20); | |
124 | ////Console.WriteLine("Free: {0,5}MB", free); | |
125 | } | |
126 | if (free > target) return; | |
127 | ////Console.WriteLine("Target:{0,5}MB - CLEARING!", target); | |
128 | RtlAdjustPrivilege(SE_INCREASE_QUOTA_PRIVILEGE, true, false, out retv); | |
129 | RtlAdjustPrivilege(SE_PROF_SINGLE_PROCESS_PRIVILEGE, true, false, out retv); | |
130 | NtSetSystemInformation(SystemMemoryListInformation, out MemoryPurgeStandbyList, Marshal.SizeOf(MemoryPurgeStandbyList)); | |
131 | if (systemcachews) { | |
132 | SetSystemFileCacheSize(new IntPtr(-1), new IntPtr(-1), 0); | |
133 | Process[] processlist = Process.GetProcesses(); // Also free system processes working sets: | |
134 | foreach(Process p in processlist) if (p.SessionId == 0) try { EmptyWorkingSet(p.Handle); } catch (Exception) {} | |
135 | } | |
136 | } | |
137 | } | |
138 | } | |
139 | /*_*/ |