Cosa sono i byte privati, i byte virtuali, il working set?


491

Sto cercando di utilizzare l'utilità perfmon windows per eseguire il debug delle perdite di memoria in un processo.

Ecco come perfmon spiega i termini:

Working Set è la dimensione corrente, in byte, del Working Set di questo processo. Il Working Set è l'insieme di pagine di memoria toccate di recente dai thread nel processo. Se la memoria disponibile nel computer supera una soglia, le pagine vengono lasciate nel working set di un processo anche se non sono in uso. Quando la memoria libera scende al di sotto di una soglia, le pagine vengono tagliate dai gruppi di lavoro. Se sono necessari, verranno nuovamente ripristinati nel set di lavoro prima di lasciare la memoria principale.

Byte virtuali è la dimensione corrente, in byte, dello spazio di indirizzi virtuali utilizzato dal processo. L'uso dello spazio degli indirizzi virtuali non implica necessariamente l'uso corrispondente delle pagine di memoria principale o del disco. Lo spazio virtuale è limitato e il processo può limitare la sua capacità di caricare librerie.

Byte privati è la dimensione corrente, in byte, della memoria allocata da questo processo che non può essere condivisa con altri processi.

Queste sono le domande che ho:

Sono i byte privati ​​che dovrei misurare per essere sicuro che il processo stia subendo delle perdite in quanto non comporta alcuna libreria condivisa e eventuali perdite, se si verificano, verranno dal processo stesso?

Qual è la memoria totale consumata dal processo? Sono i byte virtuali o la somma dei byte virtuali e del working set?

Esiste una relazione tra byte privati, working set e byte virtuali?

Ci sono altri strumenti che danno un'idea migliore dell'utilizzo della memoria?


3
Uno strumento migliore sarebbe valgrind / helgrind, ma sfortunatamente non sotto Windows :(
Kornel Kisielewicz

È il byte privato che dovrei misurare per essere sicuro che il processo abbia delle perdite Se i byte privati di un processo non crescono, allora non ci sono perdite di memoria. Se crescono potrebbe essere dovuto a perdite di memoria e potrebbe essere dovuto alla frammentazione della memoria. Penso che sia difficile dire guardando alla crescita di byte privati cosa significhi esattamente.

@SergeiKurenkov Una cosa che possiamo dire è che non sarebbe MAI dovuto alla "frammentazione della memoria".
Jamie Hanrahan,

Risposte:


517

La risposta breve a questa domanda è che nessuno di questi valori è un indicatore affidabile della quantità di memoria effettivamente utilizzata da un eseguibile e nessuno di essi è realmente appropriato per il debug di una perdita di memoria.

Byte privati si riferiscono alla quantità di memoria che l'eseguibile processo ha chiesto - non necessariamente la quantità è effettivamente utilizzando . Sono "privati" perché (di solito) escludono i file mappati in memoria (ovvero le DLL condivise). Ma - ecco il problema - non escludono necessariamente la memoria allocata da quei file . Non è possibile stabilire se una modifica dei byte privati ​​sia dovuta all'eseguibile stesso o a una libreria collegata. Anche i byte privati non sono esclusivamente memoria fisica; possono essere paginati su disco o nell'elenco delle pagine di standby (ovvero non più in uso, ma non ancora cercati).

Il working set si riferisce alla memoria fisica totale (RAM) utilizzata dal processo. Tuttavia, a differenza dei byte privati, questo include anche file mappati in memoria e varie altre risorse, quindi è una misura ancora meno accurata dei byte privati. Questo è lo stesso valore che viene riportato in "Mem Usage" di Task Manager ed è stato fonte di infinite confusioni negli ultimi anni. La memoria nel Working Set è "fisica", nel senso che può essere indirizzata senza un errore di pagina; tuttavia, l'elenco delle pagine di attesa è anche ancora fisicamente in memoria, ma non riportato nel working set, e questo è il motivo per cui si potrebbe vedere la "Mem Usage" improvvisamente cadere quando si riduce a icona di un'applicazione.

I byte virtuali sono lo spazio degli indirizzi virtuali totali occupato dall'intero processo. Questo è come il set di lavoro, nel senso che include file mappati in memoria (DLL condivise), ma include anche i dati nell'elenco di standby e i dati che sono già stati pagati e si trovano in un file di paging sul disco da qualche parte. I byte virtuali totali utilizzati da ogni processo su un sistema sotto carico pesante si sommano a una quantità di memoria significativamente maggiore di quella effettivamente fornita dalla macchina.

Quindi le relazioni sono:

  • I byte privati ​​sono ciò che la tua app ha effettivamente allocato, ma includono l'utilizzo del file di paging;
  • Il working set è costituito da byte privati ​​non paginati più file mappati in memoria;
  • I byte virtuali sono il working set più i byte privati ​​paginati e l'elenco di standby.

C'è un altro problema qui; così come le librerie condivise possono allocare memoria all'interno del modulo dell'applicazione, portando a potenziali falsi positivi riportati nei Byte privati ​​della tua app, l' applicazione potrebbe anche finire per allocare memoria all'interno dei moduli condivisi , portando a falsi negativi . Ciò significa che in realtà è possibile che l'applicazione presenti una perdita di memoria che non si manifesta mai nei byte privati. Improbabile, ma possibile.

I byte privati ​​rappresentano un'approssimazione ragionevole della quantità di memoria utilizzata dall'eseguibile e possono essere utilizzati per aiutare a restringere un elenco di potenziali candidati per una perdita di memoria; se vedi che il numero cresce e cresce costantemente e all'infinito, vorresti controllare quel processo per individuare una perdita. Ciò, tuttavia, non può dimostrare che vi sia o meno una perdita.

Uno degli strumenti più efficaci per rilevare / correggere le perdite di memoria in Windows è in realtà Visual Studio (il collegamento va alla pagina sull'utilizzo di VS per le perdite di memoria, non la pagina del prodotto). Rational Purify è un'altra possibilità. Microsoft ha anche un documento di best practice più generale su questo argomento. Ci sono più strumenti elencati in questa domanda precedente .

Spero che questo chiarisca alcune cose! Rilevare perdite di memoria è una delle cose più difficili da fare nel debug. In bocca al lupo.


26
Temo che la tua risposta non sia del tutto corretta. I byte privati ​​si riferiscono alla quantità di memoria (RAM) richiesta dall'eseguibile del processo, non solo alla memoria fisica. Quindi puoi sicuramente ispezionare la maggior parte dei casi di perdita di memoria monitorando i byte privati. Prova :: VisualAlloc per impegnare un grosso pezzo di memoria (diciamo 1.5G). Dovresti essere in grado di vedere che i tuoi byte privati ​​sono molto più grandi del set di lavoro. Il che dimostra che il tuo "working set è costituito da byte privati ​​più file mappati in memoria" non è corretto.
Jay Zhu,

4
In realtà, credo che la comprensione della scrittura sia "Il set di lavoro è i byte privati ​​in memoria più i file mappati in memoria". E i byte privati ​​POSSONO essere scambiati - puoi vedere i byte privati ​​più grandi della memoria fisica che hai nella macchina.
Jay Zhu,

2
@Aaronaught: la tua prima affermazione sull'indicatore affidabile e appropriato per il debug è confusa. I byte privati ​​sono un indicatore affidabile di una perdita nello spazio di memoria dell'applicazione. Potrebbe essere una DLL dipendente e indiretta ma è una perdita nello spazio di memoria dell'applicazione. Puoi spiegare perché non può essere utilizzato per il debug? un dump di memoria completo del processo dell'applicazione dovrebbe dirci cosa sta consumando questa memoria. Non sono sicuro di capire perché non può essere utilizzato per il debug. Puoi far luce?
G33kKahuna,

@ G33kKahuna: Non mi è chiaro come un dump della memoria ti direbbe cosa sta consumando la memoria in alcun senso significativo - a meno che per "cosa" intendi "quali moduli", ma poi tutto ciò che hai è un'istantanea, non riesci ancora a vedere quale modulo perde effettivamente memoria nel tempo a meno che non si eseguano più dump nel tempo e in condizioni strettamente controllate. È difficile concepire una strategia di debug più inefficiente e inaffidabile. I profiler sono ovunque in questi giorni; usane uno.
Aaronaught,

1
Esegui un pieno! Objsize, questo dovrebbe mostrare tutti gli oggetti appuntati nell'heap immediato. Puoi confermare controllando l'eeheap -gc. Questo dovrebbe mostrarti dove è bloccato il volume. In genere, se non sono disponibili suggerimenti con tutti i comandi precedenti, i byte privati ​​vengono utilizzati da oggetti non raccolti in GC. Ora passa a gchandles o gcleaks. Questi comandi dovrebbero indicare quali tipi / indirizzo oggetto non possono essere mappati. Il puntatore è ancora lì ma l'oggetto non c'è più. Questo è un problema così categorico per i gestori di eventi inediti.
G33kKahuna,

10

Non si dovrebbe provare a usare perfmon, task manager o qualsiasi altro strumento simile per determinare perdite di memoria. Sono utili per identificare le tendenze, ma non molto altro. I numeri che riportano in termini assoluti sono troppo vaghi e aggregati per essere utili per un compito specifico come il rilevamento della perdita di memoria.

Una precedente risposta a questa domanda ha dato una grande spiegazione di quali sono i vari tipi.

Chiedete una raccomandazione sullo strumento: consiglio Memory Validator. Capace di monitorare applicazioni che realizzano miliardi di allocazioni di memoria.

http://www.softwareverify.com/cpp/memory/index.html

Disclaimer: ho progettato Memory Validator.


1
Non riesco nemmeno a eseguire un semplice file di classe (in Java)? Cosa dà?
jn1kk,

Sospetto che Stephen e Devil siano in qualche modo imparentati o addirittura clonati ...: D;)
Robert Koritnik,

@StephenKellett, esiste una versione di prova?
Pacerier,

@Pacerier se segui il link c'è una versione di prova per entrambe le versioni x86 e x64 appena sopra l'opzione di acquisto a sinistra della pagina.
Bradley A. Tetreault,

10

La definizione dei contatori di perfoni è stata interrotta dall'inizio e per qualche motivo sembra essere troppo difficile da correggere.

Una buona panoramica della gestione della memoria di Windows è disponibile nel video " Mysteries of Memory Management Revealed " su MSDN: tratta più argomenti del necessario per tenere traccia delle perdite di memoria (ad esempio la gestione dei set di lavoro) ma fornisce dettagli sufficienti negli argomenti pertinenti.


Per darti un suggerimento sul problema con le descrizioni del contatore perfmon, ecco la storia interna dei byte privati ​​da " Contatore delle prestazioni di byte privati ​​- Attenzione! " Su MSDN:

D: Quando un byte privato non è un byte privato?

A: Quando non è residente.

Il contatore Byte privati ​​riporta la commissione di commit del processo. Vale a dire, la quantità di spazio che è stata allocata nel file di scambio per contenere il contenuto della memoria privata nel caso in cui venga sostituito. Nota: sto evitando la parola "riservato" a causa di una possibile confusione con la memoria virtuale nello stato riservato che non è stata impegnata.


Da " Pianificazione delle prestazioni " su MSDN:

3.3 Byte privati

3.3.1 Descrizione

La memoria privata, è definita come memoria allocata per un processo che non può essere condiviso da altri processi. Questa memoria è più costosa della memoria condivisa quando più di questi processi vengono eseguiti su una macchina. La memoria privata nelle dll non gestite (tradizionali) di solito costituisce la statica C ++ ed è dell'ordine del 5% dell'insieme di lavoro totale della dll.


1
vota per gli esempi follemente buoni su come si è rotto!
Bruno Brant,

La prima citazione è errata. Allocare "Byte privati" non richiede che nulla sia "allocato nel file di scambio" (che in realtà si chiama file di paging). Non è nemmeno necessario disporre di un file di paging per "byte privati" da allocare. In realtà, l'allocazione byte privati non usa subito alcun spazio da nessuna parte , e non può mai utilizzare quanto è stato assegnato.
Jamie Hanrahan,

La seconda citazione non è molto migliore. I byte privati ​​utilizzati nel codice DLL non sono necessariamente allocati per lo più staticamente all'interno della DLL. Il codice DLL è perfettamente libero di chiamare VirtualAlloc, HeapAlloc (malloc e nuovo nel CRTL), ecc. Prova anche a descrivere la dimensione della memoria privata come percentuale della dimensione del set di lavoro, che è insensata. Il primo ha una dimensione virtuale (e sarà lo stesso per ogni uso del codice con lo stesso input) mentre il secondo è fisico (che può essere radicalmente diverso da una corsa all'altra, a seconda della quantità di memoria o - affamato la macchina è).
Jamie Hanrahan,

5

C'è una discussione interessante qui: http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/307d658a-f677-40f2-bdef-e6352b0bfe9e/ La mia comprensione di questo thread è che liberando piccole allocazioni sono non riflessa in byte privati ​​o working set.

Per farla breve:

se chiamo

p=malloc(1000);
free(p);

quindi i byte privati ​​riflettono solo l'allocazione, non la deallocazione.

se chiamo

p=malloc(>512k);
free(p);

quindi i byte privati ​​riflettono correttamente l'allocazione e la deallocazione.


7
Ciò è spiegato dal fatto che le funzioni di memoria della libreria standard C utilizzano un heap personalizzato o Win32 che è un meccanismo di gestione della memoria in aggiunta alla gestione della memoria a basso livello di processo.
Kyberias,

@Kyberias, quindi come possiamo andare oltre ?
Pacerier,

while (1) gratuito (malloc (1000)); // Questo causerebbe l'aumento dei byte privati ​​per sempre?
franckspike,

2
@franckspike: no, aumenterà fino a un certo punto (generalmente circa 4 kB, ma questo può variare) e poi si fermerà, perché il CRT riutilizzerà la memoria precedentemente liberata invece di richiedere nuove pagine dal sistema operativo.
Miral,

@Pacerier: puoi chiamare VirtualAlloc e VirtualFree.
Jamie Hanrahan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.