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