Come funziona la carica di memory / impegno in Windows 10?

Questa domanda è indotta dai seguenti fenomeni osservati regolarmente che vorrei trovare una spiegazione per:

  1. Il commit corrente è regolarmente superiore a quello di utilizzo fisico e della dimensione del file di pagine. Cosa succede con quello? Non dovrebbe essere imansible? [Questo sembra essere a causa della compressione. Che trasforma la domanda a: Perché non impegnare limite poi salire o qualcosa? Quale è il punto di compressione se non aiuta con l'utilizzo della memory?
  2. A volte questo raggiunge livelli estremi in cui il commit corrente è più che l'uso della memory fisica double!
  3. Quando la carica di impegno si riempie e le windows iniziano a chiedermi di chiudere le cose, la maggior parte del tempo la memory fisica è di circa il 60%. Questo sembra orribilmente inefficiente.

Ciò è su windows 10, come riportto da Process Explorer.

L'ultima domanda che vorrei rispondere è: posso rifiutare di gonfiare artificialmente il mio file di pagine a livelli che il mio SSD affamato per spazio non è adeguatamente dotato per gestire solo in modo da poter effettivamente utilizzare la mia memory fisica? (Oppure se non fosse pieno, vale a dire, vorrei evitare suggerimenti come "fare X / Y / Z al tuo file di pagine".)

Questo è in realtà piuttosto semplice quando si capisce che la carica di commit rappresenta solo il potenziale – ma "garantito disponibile se lo vuoi" – utilizzo della memory virtuale, mentre la RAM utilizzata + lo spazio file di pagine utilizzato è l' uso effettivo (ma non tutto l'uso).

Supponiamo che stiamo parlando di sisthemes a 32 bit, quindi lo spazio di indirizzi virtuali massimo disponibile per each process è normalmente di 2 GiB. Ora supponiamo che un programma in esecuzione in un process utilizzi VirtualAlloc (una API Win32) per "commettere" 2 MiB di memory virtuale. Come ci si aspetterebbe, questo verrà visualizzato come un addizionale 2 MiB di commissione di carica, e ci sono 2 MiB less byte disponibile nel process per future allocazioni. Ma in realtà non utilizzerà alcuna memory fisica (RAM).

La chiamata VirtualAlloc restituirà al chiamante l'indirizzo iniziale della regione assegnata; questo sarà da qualche parte nell'intervallo da 0x10000 a 0x7FFEFFFF, vale a dire circa 2 GiB. (Il primo e l'ultimo 64K o 0x10000 in esadecimale di vas in each process non vengono mai assegnati e in realtà l'eventuale indirizzo iniziale della regione assegnata sarà un po 'inferiore a quello perché deve adattarsi al di sotto di quel secondo limite.)

Ma non vi è alcun uso fisico effettivo di 2 MiB di stoccaggio ancora! Non in RAM, non nel file di pagine. (C'è una piccola struttura chiamata "Descriptor di indirizzo virtuale" che descrive l'avvio e la lunghezza della regione privata impegnata.)

Qualche tempo dopo, diciamo che il programma effettivamente accede a qualcosa in quella regione (non import where). Ciò comporterà un errore di pagina . In risposta al quale il gestore di memory del sistema operativo, in particolare la routine di gestione dei guasti delle pagine (il "pager" per breve … si chiama MiAccessFault), sarà:

  1. allocare una pagina fisica in precedenza "disponibile"
  2. impostare la voce della tabella delle pagine per la pagina virtuale accessibile per associare il numero della pagina virtuale con il numero di pagina fisica appena assegnato
  3. aggiungere la pagina fisica al set di lavoro privato di process
  4. e respingere l'errore di pagina, causando l'istruzione che ha sollevato l'errore per essere riprovato.

Hai già "guastato" una pagina (4 KiB) nel process. E l'uso della memory fisica incrementerà di conseguenza, e "disponibile" diminuirà. La commissione di carica non cambia.

Qualche volta dopo, se la pagina non è stata fatta riferimento per un po 'e la richiesta di RAM è alta, questo potrebbe accadere:

  1. la pagina viene rimossa dall'unità di lavoro di process
  2. perché è stato scritto da quando è stato inserito nel set di lavoro, viene inserito nell'elenco delle pagine modificate (altrimenti va nell'elenco delle pagine di standby). La voce della tabella di pagina riflette ancora il numero di pagina fisica della pagina della RAM, ma ora ha il suo bit "valido" chiaro, quindi la prossima volta che viene fatto riferimento un errore di pagina si verifica
  3. quando l'elenco di pagine modificato colpisce una piccola soglia, un thread modificatore di pagine modificato nel process "System" si sveglia e salva il contenuto delle pagine modificate nel file di pagina (supponendo di averlo) e …
  4. prende queste pagine dall'elenco modificato e le mette nell'elenco di standby. Sono ora considerati parte di RAM "disponibile"; ma per ora hanno ancora i loro contenuti originali da quando erano nei rispettivi processi. Ancora una volta, la commissione di carica non cambia, ma l'utilizzo della RAM e il set di lavoro privato di process scenderanno.
  5. Le pagine nell'elenco standby possono ora essere ripristinate , vale a dire utilizzate per qualcos'altro – come risolvere i difetti della pagina da qualsiasi process sul sistema o utilizzati da SuperFetch. Però…
  6. Se un process che ha perso una pagina nell'elenco modificato o in attesa cerca di accedere nuovamente prima che la pagina fisica sia repurposed (cioè abbia ancora il suo contenuto originale), l'errore della pagina viene risolto senza leggere il disco. La pagina viene semplicemente riportta nel set di lavoro di process e la voce della tabella delle pagine viene fatta "valida". Questo è un esempio di errore "soft" o "cheap". Diciamo che gli elenchi di standby e modificati costituiscono una cache di pagine di sistema che probabilmente avrà bisogno di nuovo presto.

Se non si dispone di un file di pagina, i passaggi da 3 a 5 vengono modificati in: 3. Le pagine si posizionano nell'elenco modificato, in quanto non è ansible scrivere il contenuto. 4. Le pagine si posizionano nell'elenco modificato, in quanto non è ansible scrivere il contenuto. 5. Le pagine si posizionano nell'elenco modificato, in quanto non è ansible scrivere il contenuto. Il passaggio 6 rimane lo stesso, poiché le pagine dell'elenco modificato possono essere risolte nel process che li ha persi come un difetto di pagina "soft". Ma se ciò non accade, le pagine si posizionano nell'elenco modificato finché il process deallora la corrispondente memory virtuale (forse perché il process termina).

C'è altro uso dello spazio di indirizzi virtuale e della RAM, oltre alla memory privata impegnata. Esiste lo spazio di indirizzi virtuale mappato , per i quali l'archivio di backup è un file specifico piuttosto che il file di pagine. Le pagine dei vas mappati che vengono paginate sono riflesse nell'utilizzo della RAM, ma la memory mappata non contribuisce a caricare la carica perché il file mappato fornisce l'archivio di backup: qualsiasi parte della regione mappata non presente in RAM è semplicemente mantenuta nel file mappato. Un'altra differenza è che la maggior parte dei mapping di file può essere condivisa tra processi; una pagina condivisa che è già in memory per un process può essere aggiunta ad un altro process senza tornare al disco per esso (un altro errore di pagina morbida).

E c'è un vas non pagabile , per il quale non c'è un archivio di backup perché è sempre residente in RAM. Ciò contribuisce sia all'uso della RAM riportto che alla "commissione di carica".

Questo sembra essere a causa della compressione. Che trasforma la domanda a: Perché non impegnare limite poi salire o qualcosa? Quale è il punto di compressione se non aiuta con l'utilizzo della memory?

No. Non ha niente a che fare con la compressione. La compressione della memory in Windows viene eseguita come passaggio intermedio, in pagine che altrimenti verrebbero scritte nel file di pagine. In effetti consente all'elenco delle pagine modificate di utilizzare less RAM per contenere più roba, ad un certo costo nel tempo della CPU, ma con una velocità molto maggiore di quella di I / O di pagine (anche su un SSD). Poiché il limite di commit è calcolato dalla dimensione totale di file RAM + RAM, non l'utilizzo di RAM e l'utilizzo di file di pagine, questo non influisce sul limite di commit. Il limite di impegno non cambia con quanto la RAM è in uso o per cui è in uso.

Quando la carica di impegno si riempie e le windows iniziano a chiedermi di chiudere le cose, la maggior parte del tempo la memory fisica è di circa il 60%. Questo sembra orribilmente inefficiente.

Non è che Windows sia inefficiente. Sono le applicazioni in esecuzione. Stanno impegnando molto di più di quello che stanno usando.

Il motivo per l'integer meccanismo di "commit charge" e "commit limit" è questo: Quando chiamo VirtualAlloc, dovrei controllare il valore restituito per vedere se non è zero. Se è zero, significa che il mio tentativo di allocazione non è riuscito, probabilmente perché avrebbe causato la commissione di carica per superare il limite di commit e dovrei fare qualcosa di ragionevole come provare a impegnarsi less o uscire dal programma in modo pulito. Se non è nulla, cioè un indirizzo, e mi dice che il sistema ha fatto una garanzia – un impegno, se vuoi – che comunque molti byte che ho chiesto, a partire da quell'indirizzo, saranno disponibili se sceglio di accedervi; che c'è un posto per metterlo tutto – RAM o il file di pagine. cioè non c'è ragione di aspettarsi qualsiasi tipo di fallimento nell'accesso a qualsiasi cosa all'interno della regione. Questo è buono, perché non sarebbe ragionevole aspettarmi di controllare per "ha funzionato?" su each accesso alla regione assegnata.

L'analogia "banca di prestiti in denaro"

È un po 'come una banca che offre crediti, ma rigorosamente su base contrattuale. Supponiamo che la banca inizia con un milione di dollari in contanti. Le persone vanno in banca e chiedono linee di credito in quantità diverse. Dire che la banca mi approva per una linea di credito di 100.000 dollari (creo una regione privata impegnata); questo non significa che qualsiasi denaro sia effettivamente lasciato la volta. Se in seguito effettua un prestito per, per esempio, $ 20.000 (accedo un sottogruppo della regione), che rimuove i soldi dalla banca. Ma se faccio i prestiti o no, il fatto che sono stato approvato per un massimo di $ 100K significa che la banca può successivamente approvare solo un totale di altri 900.000 dollari di linee di credito per tutti i suoi clienti. La banca non approverà il credito in eccesso rispetto alle riserve di liquidità (vale a dire non li supererà), in quanto ciò significherebbe che la banca avrebbe dovuto spostare un mutuatario approvato in precedenza quando si presentassero più tardi per prendere un prestito . Sarebbe molto brutto perché la banca si era già impegnata a permettere tali prestiti e la reputazione della banca sarebbe piombata. (Questa non è, ovviamente, come funzionano le banche reali).

Sì, questo è "inefficiente" in termini di utilizzo della banca da parte della banca. E maggiore è la disparità tra le linee di credito per i quali i clienti sono approvati e gli importi che effettivamente prestano, tanto less è efficace. Ma quella inefficienza non è colpa della banca; è colpa del cliente per chiedere tali elevate linee di credito ma solo prestare piccoli prestiti. Il model di business della banca è che semplicemente non può rifiutare un mutuatario precedentemente approvato quando si presentano per get il loro prestito – per farlo sarebbe "fatale" al cliente. Ecco perché la banca tiene attentamente conto di quanto è stato "impegnato" del fondo di prestito.

Suppongo che l'espansione del file di pagine, o l'aggiunta di un altro, sarebbe come la banca uscire e get più soldi e aggiungerlo al fondo di prestito.

Se si desidera modellare la memory mappata e non pagabile in questa analogia … non pagabile è come un piccolo prestito che è necessario disporre e tenere fuori quando si apre il tuo account. (Le strutture non pagabili che definiscono each nuovo process.) La memory focalizzata è come portre il proprio denaro lungo (il file che viene mappato) e depositarlo in banca, quindi estrarre solo parti di esso alla volta (in paginazione). Perché non pagare tutto in una volta? Non lo so, forse non hai spazio nel tuo portfoglio per tutti quei soldi. 🙂 Questo non influisce sulle capacità degli altri di prendere in prestito denaro perché il denaro depositato è sul tuo conto, non il fondo di prestito generale. Questa analogia inizia a rompersi, in particolare quando cominciamo a pensare alla memory condivisa, quindi non spingerlo troppo lontano.

Torna al sistema operativo Windows: il fatto che hai gran parte della tua RAM "disponibile" non ha niente a che fare con il commit commit e il commit limit. Se sei vicino al limite di commit che significa che il sistema operativo ha già fatto – cioè ha promesso di mettere a disposizione quando richiesto – quel tanto spazio di archiviazione. Non deve essere ancora in uso per il limite da applicare.

Posso rifiutare di gonfiare artificialmente il mio file di pagine a livelli che il mio SSD affamato per spazio non è adeguatamente dotato per gestire solo in modo da poter effettivamente utilizzare la mia memory fisica? (Oppure se non fosse pieno, vale a dire, vorrei evitare suggerimenti come "fare X / Y / Z al tuo file di pagine".)

Beh, mi dispiace, ma se sei in esecuzione al limite di commit, ci sono solo tre cose che puoi fare:

  1. Aumenta la tua RAM.
  2. Aumenta la dimensione del file di pagine.
  3. Esegui less roba in una sola volta.

Re opzione 2: È ansible inserire un secondo file di pagina su un disco rigido. Se le applicazioni non utilizzano effettivamente tutte le memorie che si impegnano – che, a quanto pare, non lo sono, poiché vedete tante RAM libera – non potrai accedere molto a tale file di pagine, per cui metterlo su un disco rigido non danni alle performance. Se la lentezza di un disco rigido vi preoccupa ancora, un'altra opzione è quella di get un piccolo SSD secondario e quindi a buon mercato e mettere il secondo file di pagine su quello. L'unico "showstopper" sarebbe un computer porttile senza possibilità di aggiungere un secondo disco "non rimovibile". (Windows non ti consente di inserire i file di pagine su unità rimovibili, come qualsiasi connessione con USB.)

Ecco un'altra risposta che ho scritto che spiega le cose da una direzione diversa.

ps: Hai chiesto di Windows 10, ma dovrei dirti che funziona allo stesso modo in each versione della famiglia NT, di nuovo a NT 3.1 e nelle versioni prerelease troppo. Ciò che è probabile che sia cambiato è l'impostazione predefinita di Windows per la dimensione del file di pagina, da size RAM di 1,5x o 1x a molto più piccole. Credo che questo sia un errore.