Visualizzazione dei risultati da 1 a 5 su 5
  1. #1
    Utente di HTML.it
    Registrato dal
    May 2005
    Messaggi
    40

    SO e processi: gestione della memoria

    Ciao a tutti,

    vorrei esporvi l'idea che mi sono fatto in relazione alla gestione della memoria da parte di un SO e quelle che invece sono le tematiche relative all'organizzazione della memoria destinata ad un programma da parte del programma stesso. Faccio questo per aver conferme, smentite e precisazioni

    Premessa: per quanto riguarda un SO io non sarò preciso nel dettaglio, il mio scopo non è quello ma far collimare le questioni lato SO con quelle lato programma in esecuzione.

    Grosso modo un SO dispone di una memoria principale (la RAM) e una memoria di massa. La memoria in cui viene caricato ciò che si sta eseguendo è la RAM ma per evitare che ogni programma abbia pesantemente a che fare con le limitazioni di spazio in RAM non si carica l'intero eseguibile (almeno non necessariamente) ma soltanto porzioni di questo, lasciando la sua copia completa in un'area della memoria di massa (da ora dirò HD) dedicata a questo meccanismo. Così facendo ogni programma è come se avesse a disposizione una memoria (virtuale) pari al numero di celle indirizzabili, che nel caso di un sistema a 32 bit sono 4 GB. Ogni volta che l'esecuzione del programma in questione va a puntare a indirizzi (relativi al programma stesso) non ancora caricati in RAM, avviene un page fault: in pratica il SO deve trovar spazio in RAM (memoria fisica) per caricare da HD le nuove parti di eseguibile chiamate in causa dall'esecuzione. Il meccanismo ovviamente è dispendioso e SO gestirà queste situazioni secondo algoritmi che minimizzino i page fault etc (non mi interessa ora entrar troppo nello specifico).

    Abbiamo quindi un eseguibile contenente (non so bene come organizzati ma anche qui per ora non andrei troppo in dettaglio per non perdere di vista l'obiettivo del mio discorso) le istruzioni e le variabili per un totale di N comandi macchina equivalenti a N celle di memoria. Tale eseguibile nelle sue istruzioni punta a indirizzi di celle relative a se stesso immaginando che la prima cella sia all'indirizzo 0 della memoria. Ha quindi un suo mondo a se stante e quando viene spezzato in parti e caricato in RAM dall'SO la rivalutazione degli indirizzi delle celle a cui puntano le istruzioni dell'eseguibile etc. son questioni del tutto trasparenti al codice eseguibile del programma in esecuzione.

    Dal punto di vista dell'eseguibile quindi vi è del codice, delle variabili e della memoria dove sono contenuti e organizzati. Qui subentra per me la visione del programma e le tematiche relative a stack, heap etc. Sono questioni che riguardano il mondo del programma in esecuzione e le questioni relative all'SO e alla gestione della memoria virtuale/fisica restano ad un livello sottostante del tutto trasparente al programma. Corretto?
    Non riesco però a capire se devo quindi immaginare l'eseguibile come codice+variabili in una memoria dedicata che al suo interno è organizzata in stack, heap etc...o se ciò che creo in runtime con new (quindi heap) sia qualcosa che va al di là della gestione interna dell'eseguibile e viene allocata in ram in tempo reale dal so. Inoltre non capisco come e se gli oggetti creati in runtime (quindi non compresi nel codice eseguibile che si lancia) siano soggetti al meccanismo di paginazione etc: restano sempre in ram o rientrano come tutto il resto nel meccanismo che a livello sottostante esegue l'SO?

    Resta però il fatto che io potrei da programma voler controllare quanta memoria virtuale e/o fisica sto occupando di modo eventualmente da "gestirla" distruggendo istanze di oggetti etc. Ciò che però mi interessa gestire, cioè che ha un valore dal punto di vista del programmatore e del programma, è la memoria fisica occupata oppure quella virtuale (che dovrebbe essere >= di quella fisica, a seconda se in ram si carica tutto o solo una parte dell'eseguibile) ? La creazione di istanze in runtime fa aumentare la memoria fisica sempre o potrebbero in intervalli temporali finire su memoria di massa e quindi non incidere in ram?

    Spero di non aver fatto troppa confusione, grazie a tutti

  2. #2
    Utente di HTML.it L'avatar di Stoicenko
    Registrato dal
    Feb 2004
    Messaggi
    2,254
    1) sei bello OT
    2) discorso interessante ma con qualche svista di troppo.. per esempio in sistemi a 32 vit se non erro la memoria vistuale assegnabile ad un processo è 2 gb e non 4
    3) quando parli di aumento della memoria fisica o di aumento della memoria virtuale che il tuo programma può fare devi considerare che, la memoria fisuìica, aumenta solo se usi file sul disco.
    Ameno che tu non consideri la memoria che il sistema operativo usa come il file di paging..

  3. #3
    Utente di HTML.it
    Registrato dal
    May 2005
    Messaggi
    40
    Originariamente inviato da Stoicenko
    1) sei bello OT
    2) discorso interessante ma con qualche svista di troppo.. per esempio in sistemi a 32 vit se non erro la memoria vistuale assegnabile ad un processo è 2 gb e non 4
    3) quando parli di aumento della memoria fisica o di aumento della memoria virtuale che il tuo programma può fare devi considerare che, la memoria fisuìica, aumenta solo se usi file sul disco.
    Ameno che tu non consideri la memoria che il sistema operativo usa come il file di paging..
    Ciao,

    1) il contenuto del topic non è coerente con il titolo? o è la sezione in cui lo ho inserito che non trovi corretta?

    2) ok, diciamo che non era quello il centro del mio discorso...
    Poi se è interessante perchè non argomenti un pò di più di modo da renderlo più costruttivo? Io ho premesso subito che quello che dicevo non ero certo fosse corretto ed ero in cerca di conferme e smentite..

    3) scusami, mi son espresso male o forse ho espresso bene il casino che ho ancora in testa.
    Quando lancio un eseguibile dal punto di vista del programmatore vedo solamente una memoria RAM che gli viene assegnata ed entro la quale viene messo il flusso di istruzioni, i dati statici etc un'area di stack e un'area di heap. I dati e le istruzioni immagino vengano in pratica copiate dall'eseguibile nella ram e in più vengano anche messe a disposizione in ram(dall'SO? in base a quale criterio?) l'area di stack e di heap. Da un punto di vista dell'eseguibile credo che queste aree siano considerate tutte adiacenti e composte da celle indirizzate dallo zero in su.

    Mi chiedo quindi se una volta avviato il processo codice+dati+stack+heap siano realmente tutti inseriti in un macroblocco di ram o se l'SO salvi il tutto in un file di paging e poi carichi in ram solo alcune parti. Inoltre mi chiedo se, supposto l'uso del file di paging (swap), anche stack e heap siano soggetti a possibile caricamento/scaricamento in ram o se solo alcune parti del processo possono esserne soggette. Collegato a questo discorso quindi finisco per interrogarmi su cosa un programmatore debba tener sotto controllo da programma se vuole aver una fotografica di quanto il suo processo stia impattando sul sistema: la memoria virtuale occupata (cioè codice+dati+stack+heap in parte magari in ram e in parte salvata su file di paging) oppure solo quella fisica (cioè la parte di ram impegnata)?

    Magari sto dicendo cose inesatta o del tutto errate, per questo ho scritto qua...inoltre credo sia un argomento interessante e in rete si trova molto ma, a mio parere, poco che dia un quadro completo.

    Grazie per la pazienza (su cui confido ;-) )

    Ciao

  4. #4

    Re: SO e processi: gestione della memoria

    Originariamente inviato da Bado80
    Grosso modo un SO dispone di una memoria principale (la RAM) e una memoria di massa. La memoria in cui viene caricato ciò che si sta eseguendo è la RAM ma per evitare che ogni programma abbia pesantemente a che fare con le limitazioni di spazio in RAM non si carica l'intero eseguibile (almeno non necessariamente) ma soltanto porzioni di questo, lasciando la sua copia completa in un'area della memoria di massa (da ora dirò HD) dedicata a questo meccanismo.
    Di solito in realtà se non si ha a che fare con eseguibili mastodontici viene caricato l'intero eseguibile, visto che, rispetto alle dipendenze e soprattutto alla memoria allocata durante l'esecuzione, le sue dimensioni sono risibili rispetto alla RAM disponibile attualmente.
    Così facendo ogni programma è come se avesse a disposizione una memoria (virtuale) pari al numero di celle indirizzabili, che nel caso di un sistema a 32 bit sono 4 GB.
    Non è così semplice: lo spazio di indirizzi virtuale viene solitamente spezzato in due, con una parte accessibile solo in usermode (di solito 2 o 3 GB) e l'altra in kernelmode (2 o 1 GB); questo perché anche il kernel alloca della memoria relativa a ciascun processo. Considera inoltre che ci sono delle pagine di memoria del kernel che sono comuni a tutti i processi (che so, la lista dei processi, alcune strutture dati dei driver) che devono essere sempre mappate in memoria perché il sistema operativo possa funzionare. Non solo, ce ne sono alcune addirittura che non possono essere mai lasciate su disco, ma devono essere sempre in memoria fisica, ad esempio le strutture dati che servono al memory manager di funzionare, o altre strutture dati a cui il sistema accede continuamente.
    [quote]
    Ogni volta che l'esecuzione del programma in questione va a puntare a indirizzi (relativi al programma stesso) non ancora caricati in RAM, avviene un page fault: in pratica il SO deve trovar spazio in RAM (memoria fisica) per caricare da HD le nuove parti di eseguibile chiamate in causa dall'esecuzione./quote]
    Occhio: non si parla solo di parti di eseguibile (che, come detto, è il minore dei problemi), ma soprattutto di memoria allocata dall'eseguibile stesso. Comunque il meccanismo si applica indifferentemente a qualunque parte dello spazio di indirizzi, per cui è indifferente se l'indirizzo referenziato sia parte dell'eseguibile mappato in memoria, dello stack, dell'heap o di altra memoria ancora. L'importante però è che all'indirizzo referenziato corrisponda effettivamente qualcosa: se a questo non corrisponde memoria allocata/file mappati in memoria/... o se il programma tenta un accesso ad una pagina di memoria esistente ma in una maniera non concessa dal suo descrittore di protezione (ad esempio cerca di modificare una pagina di sola lettura) il sistema operativo, al momento del page-fault, vedrà il problema e solleverà un'eccezione di violazione di accesso.
    Il meccanismo ovviamente è dispendioso e SO gestirà queste situazioni secondo algoritmi che minimizzino i page fault etc (non mi interessa ora entrar troppo nello specifico).
    In tutto questo naturalmente entra in gioco anche il lavoro fatto dal programmatore/compilatore, che può "collaborare" con il memory manager facendo sì che il codice/i dati impiegati più di frequente stiano nella stessa pagina/in pagine vicine, in maniera da sfruttare al massimo la data locality. In questo modo si riducono al minimo i page fault nonché i cache miss.
    Abbiamo quindi un eseguibile contenente (non so bene come organizzati ma anche qui per ora non andrei troppo in dettaglio per non perdere di vista l'obiettivo del mio discorso) le istruzioni e le variabili per un totale di N comandi macchina equivalenti a N celle di memoria. Tale eseguibile nelle sue istruzioni punta a indirizzi di celle relative a se stesso immaginando che la prima cella sia all'indirizzo 0 della memoria. Ha quindi un suo mondo a se stante e quando viene spezzato in parti e caricato in RAM dall'SO la rivalutazione degli indirizzi delle celle a cui puntano le istruzioni dell'eseguibile etc. son questioni del tutto trasparenti al codice eseguibile del programma in esecuzione.
    Esattamente; a gestire la questione a livello hardware è la MMU, che viene riprogrammata dal sistema operativo ad ogni context-switch.
    Dal punto di vista dell'eseguibile quindi vi è del codice, delle variabili e della memoria dove sono contenuti e organizzati. Qui subentra per me la visione del programma e le tematiche relative a stack, heap etc. Sono questioni che riguardano il mondo del programma in esecuzione e le questioni relative all'SO e alla gestione della memoria virtuale/fisica restano ad un livello sottostante del tutto trasparente al programma. Corretto?
    Più o meno; il sistema operativo entra comunque in gioco, specialmente nella questione dell'heap.
    Non riesco però a capire se devo quindi immaginare l'eseguibile come codice+variabili in una memoria dedicata che al suo interno è organizzata in stack, heap etc...o se ciò che creo in runtime con new (quindi heap) sia qualcosa che va al di là della gestione interna dell'eseguibile e viene allocata in ram in tempo reale dal so.
    La seconda che hai detto; l'eseguibile viene caricato in memoria solitamente ad un indirizzo fisso (anche se può essere rilocato dal loader del sistema operativo, cosa che accade più di frequente nelle dll), lo stack viene creato dal sistema operativo e ci si fa riferimento tramite lo stack pointer (mi pare che c'entri anche lo stack segment register, ma non ti so dire con certezza); su di esso vengono allocate tutte le variabili locali. Il sistema operativo comunque entra spesso in gioco nella gestione dello stack per aumentarne/diminuirne le dimensioni, anche se comunque le sue dimensioni massime sono limitate.
    Le variabili globali, invece, dispongono di uno spazio preallocato nello stesso eseguibile, che, una volta caricato in memoria, viene marcato come copy-on-write. L'heap è una questione un po' più complicata, nel senso che può essere gestito direttamente dal sistema, oppure la CRT può fare da tramite (allocando solo grossi blocchi con l'allocatore del sistema e gestendola poi come meglio crede per l'applicazione), o ancora, si può usare un allocatore personalizzato (anch'esso chiede grossi blocchi all'allocatore del sistema e poi li gestisce in maniera particolare, a seconda dello scopo per cui è stato progettato).
    Inoltre non capisco come e se gli oggetti creati in runtime (quindi non compresi nel codice eseguibile che si lancia) siano soggetti al meccanismo di paginazione etc: restano sempre in ram o rientrano come tutto il resto nel meccanismo che a livello sottostante esegue l'SO?
    Si trovano sempre e comunque nello spazio di indirizzi virtuale, per cui sono soggetti alla paginazione.
    Resta però il fatto che io potrei da programma voler controllare quanta memoria virtuale e/o fisica sto occupando di modo eventualmente da "gestirla" distruggendo istanze di oggetti etc. Ciò che però mi interessa gestire, cioè che ha un valore dal punto di vista del programmatore e del programma, è la memoria fisica occupata oppure quella virtuale (che dovrebbe essere >= di quella fisica, a seconda se in ram si carica tutto o solo una parte dell'eseguibile) ? La creazione di istanze in runtime fa aumentare la memoria fisica sempre o potrebbero in intervalli temporali finire su memoria di massa e quindi non incidere in ram?
    Lascia questi mestieri al sistema operativo e agli implementatori di garbage-collector. Se programmi in linguaggi con puntatori limitati ad eliminare gli oggetti quando non ti servono più (gli smart pointers possono aiutare), e, in caso di dubbio, effettua un profiling dell'applicazione per vedere quale approccio paga di più. Nei linguaggi con gestione della memoria automatica, invece, solitamente te ne puoi in una certa misura disinteressare.

    Comunque se sei interessato alla gestione della memoria e al funzionamento dei sistemi operativi non posso che consigliarti un grande classico, Modern Operating Systems di A. Tanenbaum. L'ho letto quest'estate e mi ha fatto veramente capire molto.
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Utente di HTML.it
    Registrato dal
    May 2005
    Messaggi
    40
    Grazie MItaly, sia per la risposta sia per il suggerimento del libro (io un Tanenbaum già lo ho ma dedicato alle reti di calcolatori e mi son trovato molto bene).

    Non è che io volessi mettermi a sostituire il garbage collector ... in sintesi il mio programma genere N thread che compongono una catena di lavorazione su pacchetti di dati. Questi pacchetti vengono creati dal primo thread della catena, che legge da un file. Siccome il file può essere anche molto grosso io vorrei far in modo che se in circolo ci sono troppi pacchetti perchè il blocco lettore è più svelto a immetterli di quanto la catena lo è a smaltirli....allora il lettore rallenta il suo ritmo di immissione di pacchetti nella catena. Pensavo quindi di rendere configurabile la memoria che si è disposti ad impegnare e monitorarla...e di conseguenza rallentare il lettore se necessario.

    Ciao

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.