Domanda

È risaputo che le applicazioni Windows di solito hanno 2 GB di spazio di indirizzi privati ​​su un sistema a 32 bit.Questo spazio può essere esteso a 3Gb con l'opzione /3Gb.

Il sistema operativo si riserva i rimanenti 4Gb.

La mia domanda è: PERCHÉ?

Codice in esecuzione in modalità kernel (ad es.codice driver del dispositivo) ha il proprio spazio di indirizzi.Perché, oltre a uno spazio di indirizzi esclusivo di 4 Gb, il sistema operativo vuole comunque riservare 2 Gb per ciascun processo in modalità utente?

Pensavo che il motivo fosse la transizione tra la modalità utente e la chiamata in modalità kernel.Ad esempio, una chiamata a NtWriteFile avrà bisogno di un indirizzo per la routine di invio del kernel (ecco perché il sistema riserva 2Gb in ciascuna applicazione).Ma, usando SYSENTER, il numero del servizio di sistema non è sufficiente affinché il codice in modalità kernel sappia quale funzione/servizio viene chiamato?

Se potessi chiarirmi perché è così importante che il sistema operativo prenda 2 Gb (o 1 Gb) di ciascun processo in modalità utente.

È stato utile?

Soluzione

Due diversi processi utente hanno spazi di indirizzi virtuali diversi.Poiché le mappature degli indirizzi virtuali↔fisici sono diverse, il file TLB la cache viene invalidata quando si passano i contesti da un processo utente a un altro.Questo è molto costoso, poiché senza l'indirizzo già memorizzato nella cache nel TLB, qualsiasi accesso alla memoria risulterà in un errore e in una camminata del PTES.

Le chiamate di sistema implicano due cambi di contesto:utente→kernel, quindi kernel→utente.Per velocizzare tutto ciò, è normale riservare 1 GB o 2 GB di spazio di indirizzi virtuali superiori per l'utilizzo del kernel.Poiché lo spazio degli indirizzi virtuali non cambia tra questi cambi di contesto, non sono necessari svuotamenti TLB.Ciò è abilitato da un bit utente/supervisore in ciascun PTE, che garantisce che la memoria del kernel sia accessibile solo mentre si trova nel kernelspace;userspace non ha accesso anche se la tabella delle pagine è la stessa.

Se ci fosse il supporto hardware per due TLB separati, di cui uno esclusivamente per l'uso del kernel, questa ottimizzazione non sarebbe più utile.Tuttavia, se hai abbastanza spazio da dedicare, probabilmente vale la pena creare solo un TLB più grande.

Linux su x86 una volta supportava una modalità nota come "4G/4G split".In questa modalità, lo spazio utente ha pieno accesso all'intero spazio degli indirizzi virtuali da 4 GB e anche il kernel ha uno spazio degli indirizzi virtuali completo da 4 GB.Il costo, come già detto, è quello ogni La chiamata di sistema richiede uno svuotamento TLB, insieme a routine più complesse per copiare i dati tra la memoria dell'utente e del kernel.Questo è stato misurato per imporre fino al 30% di penalità sulle prestazioni.


I tempi sono cambiati da quando questa domanda è stata originariamente posta e ha ricevuto risposta:I sistemi operativi a 64 bit sono ora molto più diffusi.Nei sistemi operativi attuali su x86-64, indirizzi virtuali da 0 a 247-1 (0-128TB) sono consentiti per i programmi utente mentre il kernel risiede permanentemente negli indirizzi virtuali da 247×(217-1) a 264-1 (o da -247 a -1, se si trattano gli indirizzi come numeri interi con segno).

Cosa succede se esegui un eseguibile a 32 bit su Windows a 64 bit?Penseresti che tutti gli indirizzi virtuali da 0 a 232 (0-4 GB) sarebbero facilmente disponibili, ma per evitare di esporre bug nei programmi esistenti, gli eseguibili a 32 bit sono ancora limitati a 0-2 GB a meno che non vengano ricompilati con /LARGEADDRESSAWARE.Per quelli che lo sono, hanno accesso a 0-4 GB.(Questa non è una nuova bandiera;lo stesso si applicava ai kernel Windows a 32 bit in esecuzione con /3GB switch, che ha cambiato la suddivisione utente/kernel predefinita da 2G/2G a 3G/1G, anche se ovviamente 3-4GB sarebbero comunque fuori portata.)

Che tipo di bug potrebbero esserci?Ad esempio, supponiamo di implementare Quicksort e di avere due puntatori, a E b che punta all'inizio e oltre la fine di un array.Se scegli il centro come perno con (a+b)/2, funzionerà finché entrambi gli indirizzi sono inferiori a 2 GB, ma se sono entrambi superiori, l'aggiunta incontrerà un overflow di numeri interi e il risultato sarà esterno all'array.(L'espressione corretta è a+(b-a)/2.)

Per inciso, Linux a 32 bit, con la sua divisione utente/kernel predefinita 3G/1G, ha storicamente eseguito programmi con il loro stack situato nell'intervallo 2-3 GB, quindi eventuali errori di programmazione di questo tipo sarebbero probabilmente stati eliminati rapidamente.Linux a 64 bit offre ai programmi a 32 bit l'accesso a 0-4 GB.

Altri suggerimenti

Raymond Chen l'aveva fatto un sacco di articoli su questo argomento.

Windows (come qualsiasi sistema operativo) è molto più del kernel + driver.

La tua applicazione si basa su molti servizi del sistema operativo che non esistono solo nello spazio del kernel.Ci sono molti buffer, handle e tutti i tipi di risorse che possono essere mappati nello spazio degli indirizzi del tuo processo.Ogni volta che chiami una funzione API Win32 che restituisce, ad esempio, un handle di finestra o un pennello, tali elementi devono essere allocati da qualche parte nel processo.Quindi parte di Windows viene eseguita nel kernel, sì, altre parti vengono eseguite nei propri processi in modalità utente e alcune, quelle a cui la tua applicazione necessita di accesso diretto, sono mappate nel tuo spazio di indirizzi.Parte di questo è difficile da evitare, ma un importante fattore aggiuntivo sono le prestazioni.Se ogni La chiamata Win32 richiedeva un cambio di contesto, sarebbe un grave calo delle prestazioni.Se alcuni di essi possono essere gestiti in modalità utente perché i dati su cui fanno affidamento sono già mappati nel tuo spazio di indirizzi, il cambio di contesto viene evitato e risparmi parecchi cicli della CPU.

Quindi qualsiasi sistema operativo ha bisogno Alcuni quantità di spazio degli indirizzi riservata.Credo che Linux imposti di default solo 1 GB per il sistema operativo.

Il motivo per cui MS ha optato per 2 GB con Windows è stato spiegato una volta sul blog di Raymond Chen.Non ho il collegamento e non riesco a ricordare i dettagli, ma la decisione è stata presa perché Windows NT era originariamente destinato anche ai processori Alpha e su quelli Alpha c'erano VERAMENTE buone ragioni per fare il 50/50 diviso.;)

Aveva qualcosa a che fare con il supporto dell'Alpha per il codice a 32 e 64 bit.:)

Il codice eseguito in modalità kernel (ovvero il codice del driver del dispositivo) ha il proprio spazio di indirizzi.

No non lo fa.Deve condividere lo spazio degli indirizzi con la parte in modalità utente di un processo su processori x86.Ecco perché il kernel deve riservare spazio sufficiente in totale e delimitare lo spazio degli indirizzi.

Credo che la risposta migliore sia che i progettisti del sistema operativo ritenessero che, nel momento in cui se ne sarebbe dovuto preoccupare, le persone avrebbero utilizzato Windows a 64 bit.

Ma ecco un discussione migliore.

Parte della risposta ha a che fare con la storia delle architetture dei microprocessori.Ecco alcune delle cose che so, altri possono fornire dettagli più recenti.

Il processore Intel 8086 aveva un'architettura con offset di segmento per la memoria, fornendo indirizzi di memoria a 20 bit e quindi una memoria fisica indirizzabile totale di 1 MB.

A differenza dei processori concorrenti dell'epoca - come lo Zilog Z80 - l'Intel 8086 ne aveva solo uno spazio degli indirizzi che doveva ospitare non solo la memoria elettronica, ma tutte le comunicazioni di input/output con periferiche minori come tastiera, porte seriali, porte per stampanti e display video.(Per confronto, Zilog Z80 aveva uno spazio di indirizzi di input/output separato con codici operativi di assemblaggio dedicati per l'accesso)

La necessità di lasciare spazio per una gamma sempre crescente di espansioni periferiche ha portato alla decisione originale di segmentare lo spazio degli indirizzi in memoria elettronica da 0-640K e "altre cose" (ingresso/uscita, ROM, memoria video, ecc.) da 640K a 1 MB.

Man mano che la linea x86 cresceva e si evolveva, e i PC si evolvevano con essa, sono stati utilizzati schemi simili, che terminano con l'attuale divisione 2G/2G dello spazio degli indirizzi 4G.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top