Можно ли отформатировать всю память в 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, выполняют это, просто распределяя большой кусок ОЗУ, заставляя другие вещи переходить на диск на диск, что эффективно выполняет то, что вы хотите.