2012-10-11 39 views
2

最近我有一些問題,我的系統內存不足。花了一段時間才知道發生了什麼,但我最終確定,當我從文件共享中將大量數據複製到我的機器時,等量大量的內存被置於「待機」狀態。任務管理器似乎沒有顯示備用內存使用情況,但是資源監視器的確如此。起初,我只能通過重新啓動來恢復內存,但最終我發現SysInternals的人寫了一個很棒的工具來釋放內存(下面的鏈接)。以編程方式清除Windows 7的待機內存

這裏是備用存儲器的一個簡短的Blurb:

的待機列表包含已經從進程工作集,從而有效地使待機列表中的高速緩存中刪除未修改的頁面。如果進程需要處於備用列表中的頁面,則內存管理器會立即將該頁面返回到其工作集。 待機列表中的所有頁面都可用於內存分配請求。如果一個進程請求內存,內存管理器可以從備用列表中取出一個頁面,對其進行初始化並分配給調用進程。這被稱爲重新調整頁面。 待機列表中的頁面通常來自最近使用的文件。通過將這些頁面保留在備用列表中,內存管理器可減少從磁盤讀取信息的需求。磁盤讀取可能會降低系統響應速度。

(這是從這裏的文件:Memory Sizing Guidance

下面是該工具的鏈接: RAMMap

我的問題是:?

有沒有人有一個想法如何編程方式做到這一點理想我想使用C#,但我會很感激任何可能幫助我得到答案的指針。

謝謝!

+0

很明顯,它可能以編程方式做到這一點,因爲已經有一個工具。你只需要弄清楚如何去做,所以要弄清楚這個工具是如何工作的,而且你已經解決了這個問題。 –

+1

確實。但我沒有源代碼,因此我的帖子。 – chrismead

+1

馬克Russinovich從不分享他的祕密。 –

回答

2

這個祕密似乎在Process Hacker源代碼中(這是用c語言編寫的)。查看代碼,您將看到一個有前途的命令MemoryPurgeStandbyList,這似乎在我們選擇GUI中的「空待機列表」選項時被調用。

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

http://processhacker.sourceforge.net/

也可以在這裏爲command line version.

2

這概括了實現這一目標的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; 

} 

需要另外這裏的一些文檔的鏈接在網站的基本步驟其中記錄了SetIncreasePrivilege方法,並且還包含有關該主題的許多有用資源:http://www.pinvoke.net/default.aspx/ntdll/NtSetSystemInformation.html

3

這是我的代碼,它是一個控制檯應用程序,必須以管理員權限運行。代碼是C#。 使用EmptyWorkingSet和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 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; 
    const int MemoryEmptyWorkingSets = 2; 

    //Import of DLL's (API) and the necessary functions 
    [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")] 
    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 
     string ProcessName = string.Empty; 
     Process[] allProcesses = Process.GetProcesses(); 
     List<string> successProcesses = new List<string>(); 
     List<string> failProcesses = new List<string>(); 

     //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(); 
    } 
} 
} 
相關問題