Возможно ли удалить всю память в Windows? - PullRequest
11 голосов
/ 30 мая 2010

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

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

Ответы [ 3 ]

10 голосов
/ 31 мая 2010

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


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

  1. Выделите небольшой кусок памяти X, возможно, 4 МБ. (Должно ли оно быть нестраничным?)
  2. Итерация по всем процессам:
    • Для каждого процесса скопируйте куски его памяти в 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);
}

Вопрос: состоит ли регион, размер которого увеличивается на 1, не более одной страницы или я пропускаю страницы? Должен ли я попытаться выяснить размер страницы, а также увеличить ее только на минимальный размер области и размер страницы? Обновление 2: Размер страницы составляет всего 4 КБ! Я изменил вышеупомянутый код, чтобы увеличить только в 4kiB шагах. В последнем коде мы избавились бы от fprintf внутри цикла.

8 голосов
/ 30 мая 2010

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

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

0 голосов
/ 30 мая 2010

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

...