%--------------------------------------------------------------------
\chapter{La gestione della memoria} \label{chap:mem}
%--------------------------------------------------------------------

        \begin{chapterquote}
	Minnet, jag har tappat mitt minne, \\
	\"ar jag svensk eller finne \\
	kommer inte ih\aa g\dots \\
	(Bosse \"Osterberg) \\
        \end{chapterquote}

	\noindent
	Questa sezione descrive le caratteristiche di gestione della memoria di Linux, cioè la memoria virtuale e la cache di buffer del disco. Ne vengono descritti lo scopo, il funzionamento e le azioni necessarie da parte dell'amministratore di sistema.
	
\section{Cos'è la memoria virtuale?}

	Linux supporta la \defin{memoria virtuale}, cioè usa un disco come estensione della RAM in modo che la dimensione della memoria utilizzabile cresca in corrispondenza. Il kernel scrive il contenuto dei blocchi di memoria che al momento non viene utilizzata sull'hard disk, in modo che la memoria possa essere usata per altre cose. Quando il contenuto originale serve di nuovo viene rimesso in memoria. Questo processo è completamente trasparente all'utente: i programmi che girano sotto Linux vedono soltanto una memoria disponibile più grande del vero, e non sanno che parte di essa risiede sull'hard disk. Naturalmente leggere e scrivere sull'hard disk è più lento (dell'ordine di un migliaio di volte) che usare la memoria vera, quindi i programmi non sono ugualmente veloci. La parte dell'hard disk che viene usato come memoria virtuale si chiama \defin{spazio di swap}.

	Linux può usare come spazio di swap sia un file normale nel filesystem che una partizione separata; una partizione è più veloce, ma è più facile modificare la dimensione di un file (non c'è bisogno di ripartizionare l'intero hard disk, e probabilmente installare tutto da zero). Quando sapete la quantità di spazio di swap di cui avete bisogno vi conviene usare una partizione di swap, ma se non siete sicuri create un file di swap, usate il sistema per un po' per vedere di quanto spazio avete bisogno, e poi fate una partizione di swap quando siete sicuri sulla sua dimensione.

	Dovreste anche sapere che Linux permette di usare diversi file e partizioni di swap nello stesso momento. Per questo, se vi serve per un periodo una quantità particolare di spazio di swap, potete impostare un file di swap temporaneo, invece di tenerlo tutto sempre allocato.

	Una nota sulla terminologia dei sistemi operativi: l'informatica di solito distingue tra lo swapping (scrivere tutto il processo nello spazio di swap) e il paging (scriverci solo delle parti di dimensione fissa, di solito alcuni kilobyte, alla volta). Il paging di solito è più efficiente, ed è quello che fa Linux, ma la terminologia tradizionale di Linux parla comunque di swapping.\footnote{Facendo quindi innervosire in modo spaventoso moltissimi informatici.}


\section{La creazione di uno spazio di swap}

	Un file di swap è un file ordinario: non viene considerato in maniera speciale dal kernel. L'unica cosa che importa al kernel è che non deve avere buchi, e che sia preparato all'uso con \cmd{mkswap}. Deve risiedere su un disco locale, comunque, e non può risiedere su un filesystem montato via NFS per ragioni di implementazione.

	La parte sui buchi è importante: il file di swap riserva lo spazio disco in modo che il kernel possa fare velocemente lo swap di una pagina senza dover fare tutti i passi necessari per allocare un settore di un disco ad un file. Il kernel usa semplicemente i settori che sono stati allocati al file; dato che un buco nel file significa che per quel posto nel file non sono allocati settori, non è bene che il kernel provi ad usarli.

	Un modo buono per creare il file di swap senza buchi è usando questo comando:
		%
		\begin{tscreen}
\verb|$| {\sl dd if=/dev/zero of=/extra-swap bs=1024 count=1024}\\
\verb|1024+0 records in| \\
\verb|1024+0 records out| \\
\verb|$|
		\end{tscreen}
		%
	dove  \fn{/extra-swap} è il nome del file di swap e la sua dimensione viene data dopo \texttt{count=}. \`E meglio che la dimensione sia un multiplo di 4, perché il kernel manda in swap \defin{pagine di memoria} di 4 kilobyte. Se la dimensione non è un multiplo di 4 l'ultimo paio di kilobyte può restare inutilizzato.

	Anche una partizione di swap non è in nessun modo una partizione speciale. La si crea come una qualsiasi altra partizione, l'unica differenza è che viene usata così com'è, e non contiene un filesystem. \`E una buona idea segnare le partizioni di swap come tipo 82 (Linux swap); in questo modo renderete più chiara la tabella delle partizioni, anche se non è strettamente necessario per il kernel.

Dopo che avete creato un file o una partizione di swap bisogna scrivere al suo inizio una firma che contiene delle informazioni di amministrazione e viene usata dal kernel. Il comando per farlo è \cmd{mkswap}, che si usa così:
		%
		\begin{tscreen}
\verb|$| {\sl mkswap /extra-swap 1024} \\
\verb|Setting up swapspace, size = 1044480 bytes| \\
\verb|$|
		\end{tscreen}
		%
Notate che lo spazio di swap non è ancora in uso: esiste, ma il kernel non lo usa per fornire memoria virtuale.

	Dovreste stare molto attenti ad usare \cmd{mkswap}, dato che non controlla che il file o la partizione non siano usati per altre cose. \emph{Potete facilmente sovrascrivere file e partizioni importanti!}. Per fortuna dovete usare \cmd{mkswap} solo quando si installa il sistema.

	Il gestore di memoria di Linux limita la dimensione di ciascuno spazio di swap a circa 127~MB (per varie ragioni tecniche, il limite reale è  $(4096-10)\times 8\times 4096 = 133890048$ byte, o 127.6875 megabyte).  Potete comunque usare fino a 16 spazi di swap simultaneamente, per un totale di circa 2~GB.\footnote{Un gigabyte qui, un gigabyte là, presto cominceremo a parlare di memoria vera.}

\section{Come si usa lo spazio di swap}

	Uno spazio di swap inizializzato si mette in uso con \cmd{swapon}, che dice al kernel che può essere utilizzato. Come argomento viene dato il percorso per lo spazio, quindi per cominciare ad usare uno spazio di swap temporaeno si può fare:
		%
		\begin{tscreen}
\verb|$| {\sl swapon /extra-swap} \\
\verb|$|
		\end{tscreen}
		%
	Gli spazi di swap possono essere usati automaticamente elencandoli nel file \fn{/etc/fstab}.
		%
		\begin{tscreen}
\verb|/dev/hda8        none        swap        sw     0     0| \\
\verb|/swapfile        none        swap        sw     0     0|
		\end{tscreen}
		%
	Lo script di avvio fa partire il comando \texttt{swapon -a}, che comincerà a fare swap su tutti gli spazi elencati in \fn{/etc/fstab}. Il comando \cmd{swapon} è quindi necessario solo se si usano spazi di swap supplementari.
	
	Si può monitorare l'utilizzo degli spazi di swap usando il comando \cmd{free}, che dice la quantità totale di spazio di swap usata.
		%
		\begin{tscreen}
\verb|$| {\sl free} \\
\verb|             total       used       free     shared    buffers| \\
\verb|Mem:         15152      14896        256      12404       2528| \\
\verb|-/+ buffers:            12368       2784| \\
\verb|Swap:        32452       6684      25768| \\
\verb|$|
		\end{tscreen}
		%
	La prima linea di output (\verb|Mem:|) mostra la memoria fisica. La colonna ``total'' non considera la memoria fisica usata dal kernel, che in genere è circa un megabyte. La colonna ``used'' mostra la quantità di memoria usata (la seconda linea non conta i buffer). La colonna ``free'' mostra la memoria totalmente inutilizzata; la colonna ``shared''  quella condivisa da diversi processi: più è, meglio è. La colonna ``buffer'' mostra la dimensione corrente della cache di buffer del disco.

	L'ultima linea (\verb|Swap:|) mostra le stesse informazioni per gli spazi di swap. Se questa linea contiene tutti zero, non avete attivato lo spazio di swap.

	Le stesse informazioni sono disponibili con \cmd{top}, o usando il filesystem \texttt{proc}, in particolare il file \fn{/proc/meminfo}. Al momento è difficile avere delle informazioni sull'uso di uno spazio di swap specifico.	

	Uno spazio di swap può essere disabilitato con \cmd{swapoff}; in genere non è necessario farlo, tranne che per gli spazi di swap temporanei. 
	Le pagine in uso nello spazio di swap vengono per prima cosa copiate nella memoria; se non c'è memoria fisica sufficiente vengono messe in un altro spazio di swap. Se non c'è abbastanza memoria virtuale per mantenere tutte le pagine Linux comincerà a fare rumore; dopo un po' di tempo dovrebbe tornare normale, ma nel frattempo il sistema è inutilizzabile. Bisognerebbe sempre controllare (ad esempio con \cmd{free}) se c'è abbastanza memoria prima di disabilitare uno spazio di swap.

	Tutti gli spazi di swap che vengono usati automaticamente con \texttt{swapon -a} possono essere disabilitati con \texttt{swapoff -a}, che va a guardare in \fn{/etc/fstab} per vedere quali spazi rimuovere. Gli spazi di swap attivati manualmente rimarranno in uso.

	Talvolta può venire usato molto spazio di swap anche se c'è molta memoria fisica libera; ad esempio se ad un certo punto c'è bisogno di fare swap, ma poi un processo grande che occupava molta memoria fisica termina e libera la memoria. I dati messi in swap non vengono reinseriti in memoria automaticamente, ma solo quando servono, quindi la memoria fisica può restare libera per parecchio tempo. Non c'è bisogno di preoccuparsene, ma può essere confortante sapere cosa sta succedendo.

\section{La condivisione dello spazio di swap con altri sistemi operativi}

	La memoria virtuale viene usata da molti sistemi operativi; dato che ne hanno bisogno solo mentre stanno funzionando, cioè mai allo stesso tempo, gli spazi di swap di tutti i sistemi operativi presenti meno uno vanno sprecati. Sarebbe più efficiente se condividessero un solo spazio di swap. \`E possibile, ma richiede un po' di impegno. Il Tips-HOWTO contiene dei suggerimenti su come fare.


\section{Allocare lo spazio di swap} \label{sec:swap-alloc}

	Alcuni vi diranno di allocare uno spazio di swap corrispondente al doppio della vostra memoria fisica, ma è una regola fittizia. Ecco come fare in modo corretto:

    \begin{enumerate}

    \item

	Stimate di quanta memoria avete bisogno: calcolate la quantità più alta di memoria di cui avrete mai bisogno in una volta sola, cioè la somma di fabbisogno di memoria di tutti i programmi che volete far girare contemporaneamente. Lo potete fare facendo girare tutti i programmi che pensate di dover usare contemporaneamente.

	Ad esempio, se volete usare X dovreste allocargli circa 8 MB, gcc vuole qualche megabyte (alcuni file hanno bisogno di moltissima memoria, fino a decine di megabyte, ma di solito quattro bastano), e così via. Il kernel userà per sé circa un megabyte, e i normali programmi di shell usano qualche centinaia di kilobyte (diciamo un megabyte tutti insieme). Non c'è bisogno di tentare di essere esatti, basta una stima rozza, magari dal lato pessimistico. 

	Ricordatevi che se ci sono diverse persone che usano il sistema in contemporanea consumeranno tutti della memoria; comunque, se due persone usano lo stesso programma contemporaneamente l'uso complessivo di memoria non è di solito doppio, dato che le pagine di codice e le librerie condivise vengono usate solo una volta.
	
	Per stimare le necessità di memoria sono utili i comandi \cmd{free} e \cmd{ps}.

    \item

	Aggiungete un po' di memoria alla stima del passo 1 per sicurezza: la dimensione di alcuni programmi sarà sbagliata, o forse vi dimenticherete alcuni programmi che volete usare, ed è meglio avere un po' di spazio extra per qualsiasi evenienza. Un paio di megabyte dovrebbero andare bene (è meglio allocare troppo spazio di swap che troppo poco, ma non c'è bisogno di strafare e allocare l'intero disco, dato che lo spazio di swap inutilizzato è sprecato; vedi più avanti come fare per aggiungere altro swap). Inoltre, dato che si lavora meglio con i numeri pari, arrotondate il valore al megabyte superiore.

	
    \item

	Basandovi sul calcolo qui sopra sapete di quanta memoria avete bisogno in totale. Per allocare lo spazio di swap dovete dunque sottrarre la dimensione della memoria fisica dalla memoria totale, e saprete di quanto spazio di swap avete bisogno (in alcune versioni di UNIX dovete allocare dello spazio di swap anche per un'immagine della memoria fisica, quindi il totale calcolato nel passo 2 è lo swap necessario, e non dovete fare la sottrazione).


    \item

	Se lo spazio di swap calcolato è molto più grande della memoria fisica (più del doppio) dovreste investire in più memoria fisica, altrimenti le prestazioni saranno troppo basse.

    \end{enumerate}
    
	\`E una buona idea avere comunque dello spazio di swap, anche se i calcoli indicano che non ne avete bisogno. Linux usa lo spazio di swap in modo piuttosto aggressivo, in modo che possa essere tenuta libera il più memoria fisica possibile. Linux manderà in swap delle pagine di memoria che non vengono usate anche se non c'è ancora bisogno di memoria per altre cose. Un comportamento del genere evita di aspettare lo swap nel momento in cui ce n'è bisogno---si può fare prima, quando il disco altrimenti non è utilizzato.

Lo spazio di swap può essere suddiviso tra vari dischi, in modo da poter in qualche modo migliorare le prestazioni, a seconda delle velocità e degli schemi di accesso ai dischi. Potete fare degli esperimenti, ma farlo in modo corretto non è semplice. Non credete a chi dice che uno schema è sicuramente superiore ad un altro, perché non sempre è vero.

\section{La cache di buffer}
\label{sec:buffer-cache}

	Leggere da un disco\footnote{Eccetto un disco di RAM, per ovvie ragioni.} è molto più lento che accedere a della memoria (reale). Oltre a ciò, è comune leggere la stessa parte del disco diverse volte in brevi periodi di tempo. Ad esempio, si può prima leggere un messaggio di posta elettronica, poi caricare il messaggio in un editor per rispondergli, poi farlo leggere al programma di posta per copiarlo in una cartella. Oppure, considerato quanto spesso si può usare il comando \cmd{ls} su un sistema con molti utenti. Leggendo le informazioni dal disco e trattenendole in memoria finché non servono più si possono velocizzare le letture successive alla prima. Questo processo si chiama \defin{bufferizzazione del disco}, e la memoria usata allo scopo è la \defin{cache di buffer}.


	Dato che la memoria è, sfortunatamente, una risorsa finita, anzi, scarsa, la cache di buffer di solito non può essere abbastanza grande (non può contenere tutti i dati che si vogliono usare). Quando la cache si riempie, i dati che non sono stati usati per tempo più lungo vengono scartati e la memoria liberata viene usata per i nuovi dati.

	La bufferizzazione del disco vale anche in scrittura; d'altra parte, i dati scritti vengono spessi letti di nuovo (come per un codice sorgente che viene salvato in un file, e poi letto dal compilatore), quindi mettere in cache i dati che vengono scritti è una buona idea. D'altra parte, mettendo solo i dati in cache, e non scrivendoli nel disco, il programma che li scrive gira più veloce. La scrittura si può fare sullo sfondo, senza rallentare gli altri programmi.

	La maggior parte dei sistemi operativi usano la cache di buffer (anche se si può chiamare in qualche altro modo), ma non tutti funzionano con i principi descritti sotto. Alcuni sono \defin{write-through}: i dati vengono scritti tutti insieme nel disco (vengono mantenuti anche nella cache, naturalmente). La cache si chiama \defin{write-back} se la scrittura viene fatta in un secondo tempo. Il write-back è più efficiente del write-through, ma anche più soggetto ad errori: se la macchina ha un crash, o viene tolta la corrente al momento sbagliato, o il floppy viene rimosso dal drive prima che i dati nella cache vengano scritti, i cambiamenti nella cache vengono persi; ciò può anche comportare che il filesystem (se ce n'è uno) non sia pienamente funzionante, forse perché i dati non scritti contenevano cambiamenti importanti alle informazioni di archiviazione.

	Per questo non dovreste mai spegnere il computer senza usare una corretta procedura di shutdown (vedere il capitolo \ref{ch:boothalt}), o rimuovere un floppy dal drive senza smontarlo (se era stato montato) o dopo che qualsiasi programma che lo stia usando abbia segnalato di aver finito, e che il led del floppy non si sia spento. Il comando \cmd{sync} fa il \defin{flush} del buffer, cioè forza la scrittura di tutti i dati nel disco, e può essere usato quando si vuole essere certi che tutto venga scritto al sicuro. Nei sistemi UNIX tradizionali c'è un programma chiamato \cmd{update} in background che fa un \cmd{sync} ogni 30~secondi, in modo che non è in genere necessario usare \cmd{sync}. Linux ha un daemon aggiuntivo, \cmd{bdflush}, che fa un sync più imperfetto con frequenza maggiore per evitare il blocco improvviso dovuto al pesante input/output del disco che \cmd{sync} talvolta causa.

	
	Sotto Linux, \cmd{bdflush} viene avviato da \cmd{update}. Di solito non c'è ragione per preoccuparsene, ma se per qualche ragione \cmd{bdflush} muore, il kernel vi avviserà, e dovrete riavviarlo a mano (\cmd{/sbin/update}).

	La cache in genere non fa il buffer dei file, ma di blocchi, che sono le unità più piccole dell'input/output dei dischi (sotto Linux di solito sono di 1~kB). In questo modo vengono messe in cache  anche le directory, i superblocchi, altri dati di archiviazione dei filesystem e dischi non di filesystem.

	L'efficacia di una cache è principalmente decisa dalla sua dimensione. Una cache piccola è praticamente inutile: terrà talmente pochi dati che tutti i dati in cache vengono tolti prima che vengano riutilizzati. La dimensione critica dipende da quanti dati vengono letti e scritti, e da quanto spesso vengono riutilizzati gli stessi dati. L'unico modo di saperlo è sperimentare.

	Se la cache è di dimensione fissa, non è bene che sia troppo grande, perché potrebbe rendere piccola la memoria libera e rendere necessario fare swap (che è ugualmente lento). Per fare l'uso più efficiente possibile della memoria reale, Linux usa automaticamente tutta la RAM libera per la cache di buffer, ma rimpicciolisce la cache automaticamente quando i programmi hanno bisogno di più memoria.

	Sotto Linux non dovete fare niente per utilizzare la cache, ma funziona completamente in automatico. Eccetto che seguire le procedure corrette per fare shutdown e per rimuovere i floppy non ve ne dovete preoccupare.



