代码之家  ›  专栏  ›  技术社区  ›  Kerrek SB

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

  •  11
  • Kerrek SB  · 技术社区  · 15 年前

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

    有没有办法,通过windowsapi或内核调用,让Windows取消所有(或尽可能多)内存的分页?也许通过单步遍历正在运行的进程列表,让内存管理器取消每个进程的内存分页?

    3 回复  |  直到 15 年前
        1
  •  8
  •   Kevin Panko Matthew Woodard    14 年前

    嗯,你自己实施并不难。使用 VirtualQueryEx() 要发现进程使用的虚拟地址, ReadProcessMemory()

    它不太可能会有任何不同,它将只是你的程序,需要永远做它的工作。页面重新加载缓慢的常见诊断是一个零碎的页面文件。在windowsxp上很常见,例如当磁盘在很长时间内没有进行碎片整理,并且允许它经常填充接近容量的磁盘时。系统内部的 PageDefrag

        2
  •  11
  •   Kerrek SB    12 年前

    更新3: to github .


    1. 分配一小块内存X,可能是4MB(它应该是不可分页的吗?)
    2. 迭代所有进程:
      • (可能先暂停进程?)

    可能的便利和优化选项:

    • 首先检查所需的总空间是否不超过总物理空间的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: 页面大小只有4KB!我将上面的代码改为只以4kiB步递增。在最后的代码中,我们将去掉循环中的fprintf。

        3
  •  -2
  •   Billy ONeal IS4    15 年前