using System.Diagnostics;
using System.Runtime.InteropServices;
using SpdUp.Core;
namespace SpdUp.Services;
///
/// Performs real memory optimizations: working-set trimming + standby-list purge.
/// Requires administrator privileges.
///
public sealed class RamOptimizationService
{
///
/// Trim working sets of all accessible processes – pushes unused pages to the standby list.
///
public RamCleanupResult TrimWorkingSets()
{
int trimmed = 0, failed = 0;
var ownPid = Environment.ProcessId;
foreach (var proc in Process.GetProcesses())
{
try
{
if (proc.Id == ownPid || proc.Id == 0 || proc.Id == 4) continue;
var hProcess = NativeMethods.OpenProcess(
NativeMethods.PROCESS_SET_INFORMATION | NativeMethods.PROCESS_QUERY_INFORMATION,
false, proc.Id);
if (hProcess == IntPtr.Zero) { failed++; continue; }
try
{
if (NativeMethods.EmptyWorkingSet(hProcess))
trimmed++;
else
failed++;
}
finally
{
NativeMethods.CloseHandle(hProcess);
}
}
catch
{
failed++;
}
finally
{
proc.Dispose();
}
}
Logger.Info($"Working-set trim complete: {trimmed} trimmed, {failed} skipped.");
return new RamCleanupResult(trimmed, failed, 0);
}
///
/// Purge the standby memory list. Requires SeProfileSingleProcessPrivilege.
///
public bool PurgeStandbyList()
{
try
{
NativeMethods.EnablePrivilege(NativeMethods.SE_PROF_SINGLE_PROCESS_NAME);
int command = (int)NativeMethods.SYSTEM_MEMORY_LIST_COMMAND.MemoryPurgeStandbyList;
int status = NativeMethods.NtSetSystemInformation(
NativeMethods.SystemMemoryListInformation,
ref command,
Marshal.SizeOf());
if (status == 0)
{
Logger.Info("Standby list purged successfully.");
return true;
}
Logger.Warn($"NtSetSystemInformation returned NTSTATUS 0x{status:X8}");
return false;
}
catch (Exception ex)
{
Logger.Error("Failed to purge standby list", ex);
return false;
}
}
///
/// Full RAM optimisation: trim working sets + purge standby.
///
public RamCleanupResult FullCleanup()
{
var result = TrimWorkingSets();
var purged = PurgeStandbyList();
return result with { StandbyPurged = purged ? 1 : 0 };
}
///
/// Returns current memory statistics.
///
public static (ulong totalMB, ulong availMB, uint loadPercent) GetMemoryStatus()
{
var mem = new NativeMethods.MEMORYSTATUSEX { dwLength = (uint)Marshal.SizeOf() };
NativeMethods.GlobalMemoryStatusEx(ref mem);
return (mem.ullTotalPhys / 1048576, mem.ullAvailPhys / 1048576, mem.dwMemoryLoad);
}
}
public record struct RamCleanupResult(int TrimmedCount, int FailedCount, int StandbyPurged);