2009-05-14 11 views
6

Ho scritto un programma C in Linux che mallocs memoria, lo ha eseguito in un ciclo, e TOP non ha mostrato alcun consumo di memoria.Alcuni allocatori sono pigri?

quindi ho fatto qualcosa con quella memoria e TOP ha mostrato il consumo di memoria.

Quando faccio malloc, faccio veramente "memoria" o c'è una gestione della memoria "pigra", che mi dà solo la memoria se/quando la uso?

(C'è anche un'opzione che migliori conoscono solo consumo di memoria quando lo uso, quindi non sono sicuro di questo ..)

Grazie

risposta

15

Su Linux, malloc richieste di memoria con sbrk() o mmap() - in entrambi i casi, lo spazio degli indirizzi viene espanso immediatamente, ma Linux non assegna le pagine effettive della memoria fisica fino alla prima scrittura sulla pagina in questione. È possibile visualizzare l'espansione dello spazio indirizzo nella colonna VIRT, mentre l'utilizzo effettivo della memoria fisica in RES.

+0

è lo stesso per Windows? – TStamper

+0

Non ho familiarità con ciò che fa Windows, mi dispiace. – bdonlan

+0

bdonlan: Corretto, ma dovrebbe guardare fuori per l'effetto della forcella "* Il figlio non eredita i blocchi memoria del suo genitore (MLOCK (2), mlockall (2)) " Quale sarà come la maggior parte del carico di app quando sta guardando in alto – RandomNickName42

3

Sì, la memoria non è mappata nel tuo orologio a meno che non la tocchi. memoria mallocing solo configurare le tabelle di paging in modo che sappiano quando si ottiene una pagina predefinita nella memoria allocata, la memoria deve essere mappata.

0

Stai utilizzando le ottimizzazioni del compilatore? Forse l'ottimizzatore ha rimosso l'allocazione dal momento che non stai utilizzando le risorse allocate?

+0

Grazie a Ryan, ho guardato il binario con il disassemblatore e la chiamata "malloc" era lì. –

+0

+1 per contrastare i voti negativi. Questa è una buona risposta per la domanda così com'è. –

+1

Il compilatore non può rimuovere una funzione senza un'implementazione visibile o una che potrebbe avere effetti collaterali. – BeeOnRope

3

Questo inizia un po 'fuori tema (e poi lo collegherò alla tua domanda), ma quello che sta succedendo è simile a quello che succede quando batti un processo in Linux. Quando forking c'è un meccanismo chiamato copy on write che copia solo lo spazio di memoria per il nuovo processo quando viene scritta anche la memoria. In questo modo se il processo biforcato esegue un nuovo programma subito dopo hai salvato il sovraccarico di copia della memoria dei programmi originali.

Tornando alla tua domanda, l'idea è simile. Come altri hanno sottolineato, richiedendo la memoria si ottiene immediatamente lo spazio di memoria virtuale, ma le pagine effettive vengono allocate solo quando si scrive su di esse.

Qual è lo scopo di questo? Fondamentalmente rende la memoria di mallocing un'operazione di tempo più o meno costante Big O (1) invece di un'operazione di Big O (n) (simile al modo in cui lo scheduler di Linux si espande, ma invece di farlo in un unico grosso pezzo).

Per dimostrare quello che voglio dire che ho fatto il seguente esperimento:

[email protected]:~/test_code$ time ./bigmalloc 

real 0m0.005s 
user 0m0.000s 
sys 0m0.004s 
[email protected]:~/test_code$ time ./deadbeef 

real 0m0.558s 
user 0m0.000s 
sys 0m0.492s 
[email protected]:~/test_code$ time ./justwrites 

real 0m0.006s 
user 0m0.000s 
sys 0m0.008s 

Il programma bigmalloc assegna 20 milioni di interi, ma non fa nulla con loro. deadbeef scrive un int in ogni pagina risultante in 19531 scritture e justwrites assegna 19531 pollici e li azzera. Come puoi vedere, deadbeef impiega circa 100 volte di più rispetto a bigmalloc e circa 50 volte di più rispetto ai justwrites.

#include <stdlib.h>  

int main(int argc, char **argv) { 

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes 

return 0; 

} 

.

#include <stdlib.h>  

int main(int argc, char **argv) { 

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes 

// immediately write to each page to simulate all at once allocation 

// assuming 4k page size on 32bit machine 

for (int* end = big + 20000000; big < end; big+=1024) *big = 0xDEADBEEF ;  

return 0; 

} 

.

#include <stdlib.h> 

int main(int argc, char **argv) { 

int *big = calloc(sizeof(int),19531); // number of writes 

return 0; 
} 
+0

Risposta straordinaria, grazie! (È stato piuttosto sorpreso di apprendere che 0xDEADBEAF è un termine noto http://en.wikipedia.org/wiki/Hexspeak) –

0

La funzione è chiamata overcommit - kernel "promesse" Ti memoria, aumentando la dimensione del segmento dati, ma non alloca memoria fisica ad esso.Quando si tocca un indirizzo in quel nuovo spazio i difetti di pagina del processo nel kernel, che quindi tenta di mappare pagine fisiche ad esso.

0

Sì, prendere nota del VirtualAlloc bandiere,

MEM_RESERVE 
MEM_COMMIT 

.

Eh, ma per Linux, o qualsiasi POSIX/BSD/SVR# system, vfork(), è in uso da anni e fornisce funzionalità simulare.

La funzione vfork() è diverso da fork() solo in questo processo il bambino possono condividere codice e dati con il processo chiamante (processo padre). Questo velocizza l'attività di clonazione in modo significativo correndo rischi per l'integrità del processo padre se vfork() viene utilizzato in modo improprio.

L'uso di vfork() per scopi se non come un preludio ad un immediato chiamata a una funzione della famiglia exec , o per _exit(), non è consigliato.

La funzione vfork() può essere utilizzata per creare nuovi processi senza pienamente copiare lo spazio di indirizzamento del vecchio processo. Se un processo biforcuto è semplicemente andando a chiamare exec, lo spazio dati copiato dal genitore al figlio tramite forking() non è utilizzato da . Questo è particolarmente inefficiente in un ambiente paginato , rendendo particolarmente utile vfork() . A seconda di la dimensione dello spazio dati del genitore, vfork() può dare un significativo miglioramento delle prestazioni di su fork().

Problemi correlati