是否可以取消Windows中的所有内存?

时间:2010-05-30 17:31:20

标签: c windows system

我有足够的RAM,但是,在启动和完成大量进程后,似乎大多数应用程序的虚拟内存已被分页到磁盘,并且切换到任何较旧的进程需要很长时间将内存加载回RAM。

有没有办法,通过Windows API或通过内核调用,让Windows取消所有(或尽可能多)内存?也许通过逐步运行进程列表并让内存管理器取消每个进程的内存?

3 个答案:

答案 0 :(得分:10)

更新3:我上传了完整的程序to github


好的,基于到目前为止的回复,这里有一个天真的建议,试图让所有应用程序回到物理内存:

  1. 分配一大块内存X,可能是4MB。 (它应该是不可分页的吗?)
  2. 迭代所有进程:
    • 对于每个进程,将其内存块复制到X. (可能先暂停这个过程?)
  3. 假设您有2GB的RAM,并且进程实际上只需要1GB。如果一切都在物理内存中,那么你只能复制256个块,而不是世界末日。最终,所有进程现在完全都在物理内存中。

    可能的便利和优化选项:

    • 首先检查所需的总空间不超过总物理空间的50%。
    • (可选)仅在当前用户拥有的进程上运行,或在用户指定的列表上运行。
    • 首先检查每个内存块是否实际被分页到磁盘。

    我可以使用EnumProcesses()迭代所有进程;我很感激任何建议如何复制整个进程的内存块。


    更新:这是我的示例功能。它将进程ID作为其参数,并从进程的每个良好页面复制一个字节。 (第二个参数是最大进程内存大小,可通过GetSystemInfo()获得。)

    void UnpageProcessByID(DWORD processID, LPVOID MaximumApplicationAddress, DWORD PageSize)
    {
      MEMORY_BASIC_INFORMATION meminfo;
      LPVOID lpMem = NULL;
    
      // Get a handle to the process.
      HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
    
      // Do the work
      if (NULL == hProcess )
      {
        fprintf(stderr, "Could not get process handle, skipping requested process ID %u.\n", processID);
      }
      else
      {
        SIZE_T        nbytes;
        unsigned char buf;
    
        while (lpMem < MaximumApplicationAddress)
        {
          unsigned int stepsize = PageSize;
    
          if (!VirtualQueryEx(hProcess, lpMem, &meminfo, sizeof(meminfo)))
          {
            fprintf(stderr, "Error during VirtualQueryEx(), skipping process ID (error code %u, PID %u).\n", GetLastError(), processID);
            break;
          }
    
          if (meminfo.RegionSize < stepsize) stepsize = meminfo.RegionSize;
    
          switch(meminfo.State)
          {
          case MEM_COMMIT:
            // This next line should be disabled in the final code
            fprintf(stderr, "Page at 0x%08X: Good, unpaging.\n", lpMem);
    
            if (0 == ReadProcessMemory(hProcess, lpMem, (LPVOID)&buf, 1, &nbytes))
              fprintf(stderr, "Failed to read one byte from 0x%X, error %u (%u bytes read).\n", lpMem, GetLastError(), nbytes);
            else
              // This next line should be disabled in the final code
              fprintf(stderr, "Read %u byte(s) successfully from 0x%X (byte was: 0x%X).\n", nbytes, lpMem, buf);
    
            break;
          case MEM_FREE:
            fprintf(stderr, "Page at 0x%08X: Free (unused), skipping.\n", lpMem);
            stepsize = meminfo.RegionSize;
            break;
          case MEM_RESERVE:
            fprintf(stderr, "Page at 0x%08X: Reserved, skipping.\n", lpMem);
            stepsize = meminfo.RegionSize;
            break;
          default:
            fprintf(stderr, "Page at 0x%08X: Unknown state, panic!\n", lpMem);
          }
    
          //lpMem = (LPVOID)((DWORD)meminfo.BaseAddress + (DWORD)meminfo.RegionSize);
          lpMem += stepsize;
        }
      }
    
      CloseHandle(hProcess);
    }
    

    问题:我增加的大小区域最多只包含一页,还是我缺少页面?我是否应该尝试查找页面大小,并且只增加区域大小和页面大小的最小值? 更新2:页面大小仅为4kiB!我改变了上面的代码只在4kiB步骤中增加。在最终的代码中,我们将摆脱循环中的fprintf。

答案 1 :(得分:8)

嗯,实现自己并不困难。使用VirtualQueryEx()发现进程使用的虚拟地址ReadProcessMemory()以强制重新加载页面。

它根本不可能产生任何差别,它只是你的程序需要永远完成它的工作。缓慢重新加载页面的常见诊断是分段的页面文件。在Windows XP上常见,例如,磁盘在很长一段时间内没有进行碎片整理,并且允许频繁填充接近容量。 SysInternals的PageDefrag实用程序可以帮助解决问题。

答案 2 :(得分:-2)

不,Windows本身不提供此类功能。像Cacheman和RAM IDLE这样的程序通过简单地分配大块RAM来实现这一点,迫使其他东西转到磁盘,这有效地完成了你想要的东西。