Можно ли отформатировать всю память в Windows?

У меня много оперативной памяти, однако после запуска и завершения большого количества процессов кажется, что большая часть виртуальной памяти приложений была выгружена на диск, и переход на любой из старых процессов требует очень долгого времени для загрузки памяти в оперативную память.

Есть ли способ, либо через Windows API, либо через вызов ядра, чтобы заставить Windows обрезать все (или насколько это возможно) память? Может быть, перейдя через список запущенных процессов и заставить диспетчер памяти обрезать каждую память процесса?

Ответ 1

Ну, это не сложно реализовать. Используйте VirtualQueryEx() для обнаружения виртуальных адресов, используемых процессом, ReadProcessMemory(), чтобы заставить страницы перезагрузиться.

Скорее всего, это будет иметь какое-то значение, это будет ваша программа, которая навсегда будет выполнять свою работу. Общей диагностикой для медленной перезагрузки страниц является фрагментированный файл подкачки. Обычный в Windows XP, например, когда диск не был дефрагментирован в течение длительного времени, и ему было разрешено часто заполнять его часто. Утилита SysInternals PageDefrag может помочь устранить проблему.

Ответ 2

Обновление 3: Я загрузил свою полную программу в github.


ОК, на основе ответов до сих пор, наивное предложение для инструмента, который пытается вернуть все приложения в физическую память:

  • Выделите небольшой кусок памяти X, возможно, 4 МБ. (Должен ли он быть неустранимым?)
  • Итерация по всем процессам:
    • Для каждого процесса копируйте куски своей памяти в X. (Возможно, сначала приостановить процесс?)

Предположим, что у вас 2 ГБ ОЗУ, и только 1 ГБ действительно требуется процессами. Если все в физической памяти, вы копируете только 256 кусков, а не конец света. В конце концов, есть хорошая вероятность, что все процессы теперь полностью находятся в физической памяти.

Возможные варианты удобства и оптимизации:

  • Сначала проверьте, что общее требуемое пространство не более, чем, скажем, 50% от общего физического пространства.
  • Необязательно запускать только процессы, принадлежащие текущему пользователю, или в списке, указанном пользователем.
  • Сначала проверьте, действительно ли каждый фрагмент памяти выгружен на диск или нет.

Я могу выполнять итерацию по всем процессам с помощью EnumProcesses(); Я был бы благодарен за любые предложения о том, как скопировать весь процесс памяти.


Обновление: Вот моя функция. Он принимает идентификатор процесса в качестве аргумента и копирует один байт с каждой хорошей страницы процесса. (Второй аргумент - максимальный размер памяти процесса, доступный через 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 внутри цикла.

Ответ 3

Нет, окна не обеспечивают такую ​​функцию изначально. Такие программы, как Cacheman и RAM IDLE, выполняют это, просто распределяя большой кусок ОЗУ, заставляя другие вещи переходить на диск на диск, что эффективно выполняет то, что вы хотите.