Aggiornamento 3: Ho caricato il mio programma completo to github.
OK, sulla base delle risposte fino ad ora, ecco un suggerimento ingenuo per uno strumento che cerca di ottenere tutti le applicazioni di back nella memoria fisica:
- Allocare un piccolo pezzo di memoria X, forse 4MB . (Dovrebbe essere non paginabili?)
- iterare su tutti i processi:
- Per ogni processo, copiare blocchi di memoria a X. (Eventualmente sospende il processo prima?)
Supponiamo di avere 2 GB di RAM, e solo 1 GB è effettivamente richiesto dai processi. Se tutto è nella memoria fisica, copi solo 256 blocchi, non la fine del mondo. Alla fine della giornata, ci sono buone possibilità che tutti i processi siano ora interamente nella memoria fisica.
Possibili convenienza e ottimizzazione opzioni:
- Verificare prima che lo spazio totale richiesto non è più rispetto, ad esempio, il 50% dello spazio fisico totale.
- Opzionalmente può essere eseguito solo su processi di proprietà dell'utente corrente o su un elenco specificato dall'utente.
- Controllare prima se ciascun blocco di memoria è effettivamente trasferito su disco o meno.
Posso scorrere tutti i processi utilizzando EnumProcesses(); Sarei grato per qualsiasi suggerimento su come copiare la memoria di un intero processo in termini di quantità.
Aggiornamento: Qui è la mia funzione di esempio. Prende l'ID del processo come argomento e copia un byte da ciascuna pagina del processo. (Il secondo argomento è la dimensione della memoria processo di massima, ottenibile mediante 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);
}
Domanda: la regione da cui dimensione I incremento composto al massimo una pagina, o mi sto perdendo pagine? Dovrei provare a scoprire anche la dimensione della pagina e incrementare solo con il minimo delle dimensioni della regione e della dimensione della pagina?
Aggiornamento 2: La dimensione della pagina è solo 4kiB! Ho modificato il codice precedente per incrementare solo in step 4kiB. Nel codice finale ci libereremmo di fprintf all'interno del ciclo.
Grazie per entrambi questi suggerimenti! Fammi controllare se l'utilizzo delle due funzioni fa alcuna differenza sulle prestazioni dei processi di commutazione! –
Sì, perché chiamare ReadProcessMemory su ogni byte di ogni processo sicuramente funzionerà meglio delle semplici operazioni di paging in ..... Oh, a proposito, avrai bisogno di Admin preamp e prendo il privilegio SE_DEBUG_NAME per usare il processo funzioni di memoria. –
Oh, no, in realtà non voglio leggere ogni byte, voglio solo dire al gestore della memoria che potrei essere in procinto di farlo ...Sicuramente il gestore della memoria deve sapere se le parti della memoria di un processo sono state sfasate; Sono sorpreso che non abbia un'interfaccia per richiedere la memoria di paging per un processo specifico senza richiedere effettivamente il contenuto da quella memoria. Re "ogni byte di ogni processo": non mi importa se fa tutto questo in una volta mentre sono in pausa caffè, finché quando torno tutto è in memoria. –