2012-09-19 2 views
5

Sono molto nuovo a questi concetti ma voglio farti una domanda che è molto semplice, penso, ma sono confuso, quindi lo sto chiedendo. La domanda è ... Come sono determinate le dimensioni di un processo dal sistema operativo? Lasciatemi chiarire prima, supponiamo che io abbia scritto un programma in C e voglio sapere quanta memoria ci vorrà, come posso determinarlo? in secondo luogo, so che ci sono molte sezioni come la sezione di codice, la sezione di dati, il BSS di un processo. Ora la dimensione di questi è predeterminata? in secondo luogo, come vengono determinate le dimensioni di Stack e heap. la dimensione dello stack e dell'heap conta anche mentre viene calcolata la dimensione totale del processo.Come viene determinata la dimensione del processo?

Ancora una volta diciamo che quando carichiamo il programma, viene dato uno spazio di indirizzamento al processo (che è fatto dal registro di base e limite e controllato da MMU, immagino) e quando il processo tenta di accedere a una locazione di memoria che non è nel suo spazio di indirizzamento otteniamo un errore di segmentazione. Com'è possibile che un processo acceda a una memoria che non si trova nel suo spazio indirizzo. Secondo la mia comprensione, quando si verifica un overflow del buffer, l'indirizzo viene danneggiato. Ora, quando il processo vuole accedere alla posizione danneggiata, si ottiene l'errore di segmentazione. C'è un altro modo di violazione dell'indirizzo.

e, in terzo luogo, perché lo stack cresce verso il basso e si accumula. Questo processo è identico a tutto il sistema operativo. In che modo influisce sulla performance. Perché non possiamo averla in un altro modo?

Per favore correggimi, se ho torto in una qualsiasi delle affermazioni.

Grazie Sohrab

+0

Non è una domanda di programmazione. – unwind

risposta

1

Quando viene avviato un processo, ottiene il proprio spazio di indirizzamento virtuale. La dimensione dello spazio di indirizzamento virtuale dipende dal tuo sistema operativo. In generale i processi a 32 bit ottengono 4 indirizzi GiB (4 giga binari) e i processi a 64 bit ottengono 18 indirizzi EiB (18 exa binari).

Non è possibile accedere in alcun modo a qualcosa che non è mappato nello spazio degli indirizzi virtuale poiché per definizione tutto ciò che non è mappato non ha un indirizzo per voi. Puoi provare ad accedere alle aree dello spazio degli indirizzi virtuali che al momento non sono mappate a nulla, nel qual caso ottieni un'eccezione segfault.

Non tutto lo spazio degli indirizzi è mappato a qualcosa in qualsiasi momento. Inoltre, non tutti possono essere mappati (la quantità di esso può essere mappata dipende dal processore e dal sistema operativo). Su processori Intel di generazione corrente possono essere mappati fino a 256 TiB del proprio spazio indirizzo. Si noti che i sistemi operativi possono limitarlo ulteriormente. Ad esempio per processi a 32 bit (con un massimo di 4 indirizzi GiB) Windows di default riserva 2 GiB per il sistema e 2 GiB per l'applicazione (ma c'è un modo per renderlo 1 GiB per il sistema e 3 GiB per l'applicazione).

Quanta parte dello spazio indirizzo viene utilizzata e la quantità di modifiche mappate durante l'esecuzione dell'applicazione. Gli strumenti specifici del sistema operativo consentono di monitorare ciò che la memoria attualmente allocata e lo spazio degli indirizzi virtuali sono per un'applicazione in esecuzione.

La sezione di codice, la sezione dati, BSS ecc. Sono termini che fanno riferimento a diverse aree del file eseguibile creato dal linker. In generale il codice è separato dai dati statici immutabili, che è separato dai dati allocati staticamente ma mutabili. Stack e heap sono separati da tutto quanto sopra. La loro dimensione è calcolata dal compilatore e dal linker. Si noti che ogni file binario ha le proprie sezioni, quindi tutte le librerie collegate dinamicamente verranno mappate nello spazio indirizzo separatamente ciascuna con le proprie sezioni mappate da qualche parte. Heap e stack, tuttavia, non fanno parte dell'immagine binaria, in genere c'è solo uno stack per processo e un heap.

La dimensione della pila (almeno lo stack iniziale) è generalmente fissa. I compilatori e/o i linker in genere hanno alcuni flag che è possibile utilizzare per impostare la dimensione dello stack che si desidera in fase di esecuzione. Gli stack generalmente "crescono indietro" perché è così che funzionano le istruzioni dello stack del processore. La crescita degli stack in una direzione e la crescita degli altri nell'altra rendono più facile organizzare la memoria in situazioni in cui si desidera che entrambi siano illimitati, ma non si sa quanto ciascuno può crescere.

Heap, in generale, fa riferimento a tutto ciò che non è preassegnato all'avvio del processo. Al livello più basso ci sono diverse operazioni logiche che riguardano la gestione dell'heap (non tutte sono implementate come descrivo qui in tutti i sistemi operativi).

Mentre lo spazio indirizzo è fisso, alcuni SO tengono traccia di quali parti sono attualmente recuperate dal processo. Anche se questo non è il caso, il processo stesso deve tenerne traccia. Quindi l'operazione di livello più basso è effettivamente decidere che verrà utilizzata una determinata area dello spazio degli indirizzi.

La seconda operazione di basso livello è di istruire il sistema operativo per mappare quella regione su qualcosa.Questo in generale può essere

  • alcuna memoria che non è sostituibile a

  • memoria che è sostituibile e mappato al file system scambio

  • memoria che è sostituibile e mappato a qualche altro file

  • memoria che è scambiabile e mappata su un altro file in modalità di sola lettura

  • la stessa mappatura che un'altra regione indirizzo virtuale è mappato

  • la stessa mappatura che un'altra regione indirizzo virtuale è mappato, ma in modalità di sola lettura

  • la stessa mappatura che un'altra regione indirizzo virtuale è mappato , ma in copia in modalità di scrittura con i dati copiati mappati per il file di swap di default

ci possono essere altre combinazioni ho dimenticato, ma questi sono quelli principali.

Ovviamente lo spazio totale utilizzato dipende davvero da come lo si definisce. La RAM attualmente utilizzata è diversa dallo spazio indirizzo attualmente mappato. Ma come ho scritto sopra, gli strumenti dipendenti dal sistema operativo dovrebbero farti scoprire cosa sta succedendo attualmente.

1

Le sezioni sono predeterminati dal file eseguibile.

Oltre a quello, potrebbero essere presenti librerie collegate dinamicamente. Mentre il codice e i dati costanti di una DLL devono essere condivisi tra più processi che lo utilizzano e non vengono conteggiati più di una volta, i suoi dati non costanti specifici del processo devono essere considerati in ogni processo.

Inoltre, può esserci una memoria allocata dinamicamente nel processo.

Inoltre, se nel processo sono presenti più thread, ognuno di essi avrà il proprio stack.

Inoltre, ci saranno strutture dati per-thread, per processo e per libreria nel processo stesso e nel kernel per conto proprio (archiviazione locale thread, parametri della riga di comando, handle per varie risorse , strutture per quelle risorse pure e così via e così via).

È difficile calcolare esattamente le dimensioni del processo completo senza sapere come viene implementato tutto. Si potrebbe ottenere una stima ragionevole, però.

W.r.t. According to my understanding when some buffer overflows happens then the address gets corrupted. Non è necessariamente vero. Prima di tutto, l'indirizzo di cosa? Dipende da cosa succede nella memoria vicino al buffer. Se c'è un indirizzo, può essere sovrascritto durante un overflow del buffer. Ma se c'è un altro buffer nelle vicinanze che contiene un'immagine di te, i pixel dell'immagine possono essere sovrascritti.

È possibile ottenere errori di segmentazione o di pagina quando si tenta di accedere alla memoria per la quale non si dispone delle autorizzazioni necessarie (ad esempio, la parte del kernel mappata o altrimenti presente nello spazio di indirizzamento del processo). Oppure può essere una posizione di sola lettura. O la posizione non può avere alcuna mappatura sulla memoria fisica.

È difficile stabilire in che modo la posizione e il layout dello stack e dell'heap influenzeranno le prestazioni senza conoscere le prestazioni di ciò di cui stiamo parlando. Puoi speculare, ma le speculazioni possono rivelarsi sbagliate.

A proposito, dovresti prendere in seria considerazione la possibilità di porre domande separate su SO per questioni separate.

+0

grazie ... Lo terrò a mente la prossima volta ...: -) ... grazie per la spiegazione. –

1

"Com'è possibile per un processo accedere a una memoria che non si trova nel suo spazio indirizzo?"

Data la protezione della memoria è impossibile. Ma potrebbe essere tentato. Considera puntatori casuali o accesso oltre i buffer. Se si incrementa qualsiasi puntatore abbastanza a lungo, quasi certamente si perde in un intervallo di indirizzi non mappato. Semplice esempio:

char *p = "some string"; 

while (*p++ != 256) /* Always true. Keeps incrementing p until segfault. */ 
    ; 

Errori semplici come questo non sono sconosciuti, per rendere l'eufemismo.

+1

Si chiama "litote". :) – Mehrdad

+0

Grazie! Non mi dispiace affatto apprendere questo tipo di terminologia :-) – Jens

0

Posso rispondere alle domande 2 e 3.

Risposta # 2

Quando nel C si utilizzano i puntatori si sta realmente utilizzando un valore numerico che viene interpretato come l'indirizzo di memoria (indirizzo logico su sistema operativo moderno, vedi note). Puoi modificare questo indirizzo a tuo piacimento. Se il valore punta a un indirizzo che non si trova nello spazio degli indirizzi, si verifica un errore di segmentazione.

Si consideri ad esempio questo scenario: il sistema operativo assegna al processo l'intervallo di indirizzi da 0x01000 a 0x09000. Poi

int * ptr = 0x01000; 
printf("%d", ptr[0]); // * prints 4 bytes (sizeof(int) bytes) of your address space 
int * ptr = 0x09100; 
printf("%d", ptr[0]); // * You are accessing out of your space: segfault 

Per lo più le cause di segfault, come lei ha sottolineato, sono l'uso di puntatori a NULL (che è per lo più l'indirizzo 0x00, ma l'attuazione dipendente) o l'uso di indirizzi danneggiati.

Si noti che, su linux i386, i registri di base e limite non vengono utilizzati come si potrebbe pensare. Non sono limiti per processo, ma indicano due tipi di segmenti: spazio utente o spazio del kernel.

Risposta # 3

La crescita stack è dipendente dall'hardware e non dipende dal sistema operativo. Sull'i386 istruzioni di assemblaggio come push e pop fanno crescere lo stack verso il basso in relazione ai registri relativi allo stack. Ad esempio il puntatore dello stack diminuisce automaticamente quando fai una spinta e aumenta quando fai un pop. Il sistema operativo non può occuparsene.

Note

In un moderno sistema operativo, un processo utilizza il cosiddetto indirizzo logico. Questo indirizzo è mappato con l'indirizzo fisico dal sistema operativo. Per avere una nota di questa compilare autonomamente questo semplicemente programma:

#include <stdio.h> 

int main() 
{ 
    int a = 10; 
    printf("%p\n", &a); 
    return 0; 
} 

Se si esegue questo programma più volte (anche contemporaneamente) si vedrebbe, anche per diverse istanze, lo stesso indirizzo stampato. Ovviamente questo non è il vero indirizzo di memoria, ma è un indirizzo logico che verrà mappato all'indirizzo fisico quando necessario.