Effacer la mémoire de veille de Windows 7 par programme

Récemment, j’ai eu quelques problèmes avec le manque de mémoire de mon système. Il a fallu un certain temps pour découvrir ce qui se passait, mais j’ai finalement déterminé que, lorsque je copiais de grandes quantités de données sur ma machine à partir d’un partage de fichiers, une quantité de mémoire équivalente était mise en «veille». Le Gestionnaire des tâches ne semble pas afficher l’utilisation de la mémoire de réserve, contrairement à Moniteur de ressources. Au début, je ne pouvais récupérer la mémoire qu’en redémarrant, mais j’ai découvert par la suite que les gars de SysInternals avaient écrit un excellent utilitaire pour libérer la mémoire (lien ci-dessous).

Voici un bref exposé sur la mémoire en veille:

La liste de veille contient des pages non modifiées qui ont été supprimées des ensembles de travail de processus, ce qui fait de la liste de réserve un cache. Si un processus nécessite une page figurant dans la liste de veille, le gestionnaire de mémoire rétablit immédiatement la page dans son ensemble de travail. Toutes les pages de la liste de veille sont disponibles pour les demandes d’allocation de mémoire. Si un processus demande de la mémoire, le gestionnaire de mémoire peut extraire une page de la liste de secours, l’initialiser et l’affecter au processus appelant. Cela s’appelle réorienter une page. Les pages de la liste de veille sont souvent issues de fichiers récemment utilisés. En conservant ces pages dans la liste de veille, le gestionnaire de mémoire réduit le besoin de lire des informations à partir du disque. Les lectures sur disque peuvent réduire la réactivité du système.

(Ceci est tiré du document ici: Guide de dimensionnement de la mémoire

Voici un lien vers l’outil: RAMMap

Ma question est:

Quelqu’un a-t-il une idée de la procédure à suivre? Idéalement, j’aimerais utiliser C #, mais j’apprécierais tout renseignement qui pourrait m’aider à obtenir une réponse.

Merci!

Voici mon code, c’est une application console qui doit être exécutée avec des privilèges d’administrateur. Le code est C #. Utilise EmptyWorkingSet et MemoryPurgeStandbyList.

using System; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Principal; using System.Threading; using System.Collections.Generic; namespace FreeMemory { //Declaration of structures //SYSTEM_CACHE_INFORMATION [StructLayout(LayoutKind.Sequential, Pack = 1)] struct SYSTEM_CACHE_INFORMATION { public uint CurrentSize; public uint PeakSize; public uint PageFaultCount; public uint MinimumWorkingSet; public uint MaximumWorkingSet; public uint Unused1; public uint Unused2; public uint Unused3; public uint Unused4; } //SYSTEM_CACHE_INFORMATION_64_BIT [StructLayout(LayoutKind.Sequential, Pack = 1)] struct SYSTEM_CACHE_INFORMATION_64_BIT { public long CurrentSize; public long PeakSize; public long PageFaultCount; public long MinimumWorkingSet; public long MaximumWorkingSet; public long Unused1; public long Unused2; public long Unused3; public long Unused4; } //TokPriv1Luid [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct TokPriv1Luid { public int Count; public long Luid; public int Attr; } public class Program { //Declaration of constants const int SE_PRIVILEGE_ENABLED = 2; const ssortingng SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"; const ssortingng SE_PROFILE_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege"; const int SystemFileCacheInformation = 0x0015; const int SystemMemoryListInformation = 0x0050; const int MemoryPurgeStandbyList = 4; const int MemoryEmptyWorkingSets = 2; //Import of DLL's (API) and the necessary functions [DllImport("advapi32.dll", SetLastError = true)] internal static extern bool LookupPrivilegeValue(ssortingng host, ssortingng 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")] public static extern UInt32 NtSetSystemInformation(int InfoClass, IntPtr Info, int Length); [DllImport("psapi.dll")] static extern int EmptyWorkingSet(IntPtr hwProc); //Function to clear working set of all processes public static void EmptyWorkingSetFunction() { //Declaration of variables ssortingng ProcessName = ssortingng.Empty; Process[] allProcesses = Process.GetProcesses(); List successProcesses = new List(); List failProcesses = new List(); //Cycle through all processes for (int i = 0; i < allProcesses.Length; i++) { Process p = new Process(); p = allProcesses[i]; //Try to empty the working set of the process, if succesfull add to successProcesses, if failed add to failProcesses with error message try { ProcessName = p.ProcessName; EmptyWorkingSet(p.Handle); successProcesses.Add(ProcessName); } catch (Exception ex) { failProcesses.Add(ProcessName + ": " + ex.Message); } } //Print the lists with successful and failed processes Console.WriteLine("SUCCESSFULLY CLEARED PROCESSES: " + successProcesses.Count); Console.WriteLine("-------------------------------"); for (int i = 0; i < successProcesses.Count; i++) { Console.WriteLine(successProcesses[i]); } Console.WriteLine(); Console.WriteLine("FAILED CLEARED PROCESSES: " + failProcesses.Count); Console.WriteLine("-------------------------------"); for (int i = 0; i < failProcesses.Count; i++) { Console.WriteLine(failProcesses[i]); } Console.WriteLine(); } //Function to check if OS is 64-bit or not, returns boolean public static bool Is64BitMode() { return Marshal.SizeOf(typeof(IntPtr)) == 8; } //Function used to clear file system cache, returns boolean public static void ClearFileSystemCache(bool ClearStandbyCache) { try { //Check if privilege can be increased if (SetIncreasePrivilege(SE_INCREASE_QUOTA_NAME)) { uint num1; int SystemInfoLength; GCHandle gcHandle; //First check which version is running, then fill structure with cache information. Throw error is cache information cannot be read. 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(); } if (num1 != 0) throw new Exception("NtSetSystemInformation(SYSTEMCACHEINFORMATION) error: ", new Win32Exception(Marshal.GetLastWin32Error())); } //If passes paramater is 'true' and the privilege can be increased, then clear standby lists through MemoryPurgeStandbyList 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()); } } //Function to increase Privilege, returns boolean 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; //Retrieves the LUID used on a specified system to locally represent the specified privilege name if (!LookupPrivilegeValue(null, privilegeName, ref newst.Luid)) throw new Exception("Error in LookupPrivilegeValue: ", new Win32Exception(Marshal.GetLastWin32Error())); //Enables or disables privileges in a specified access token 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; } } //MAIN Program static void Main(string[] args) { //Clear working set of all processes EmptyWorkingSetFunction(); //Clear file system cache ClearFileSystemCache(true); //Waiting for input of user to close program Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } } 

Le secret semble être dans le code source de Process Hacker (qui est en langage c). En regardant le code, vous verrez une commande prometteuse, MemoryPurgeStandbyList, qui semble être appelée lorsque nous choisissons l’option “liste de réserve vide” dans l’interface graphique.

 memlists.c(227, 35): command = MemoryPurgeStandbyList; ntexapi.h(1475, 5): MemoryPurgeStandbyList, 

http://processhacker.sourceforge.net/

Également disponible ici en version de ligne de commande.

Ceci décrit les étapes de base requirejses pour y parvenir en C #.

 using System; using System.Runtime.InteropServices; using System.Security.Principal; public static class MemoryUtility { private static void ClearStandbyCache() { SetIncreasePrivilege(SE_PROFILE_SINGLE_PROCESS_NAME); int iReturn; int iSize = Marshal.SizeOf(ClearStandbyPageList); GCHandle gch = GCHandle.Alloc(ClearStandbyPageList, GCHandleType.Pinned); iReturn = NtSetSystemInformation(SYSTEMMEMORYLISTINFORMATION, gch.AddrOfPinnedObject(), iSize); gch.Free(); if (iReturn != 0) Console.WriteLine("Empty Standby List failed"); else Console.WriteLine("Empty Standby List success"); } [DllImport("NTDLL.dll", SetLastError = true)] internal static extern int NtSetSystemInformation(int SystemInformationClass, IntPtr SystemInfo, int SystemInfoLength); //SystemInformationClass values private static int SYSTEMCACHEINFORMATION = 0x15; private static int SYSTEMMEMORYLISTINFORMATION = 80; //SystemInfo values private static int ClearStandbyPageList = 4; } 

Vous trouverez également un lien vers de la documentation sur un site où la méthode SetIncreasePrivilege est documentée et contient de nombreuses ressources utiles sur le sujet: http://www.pinvoke.net/default.aspx/ntdll/NtSetSystemInformation.html