%--------------------------------------------------------------------
\chapter{Gestion mémoire} \label{chap:mem}
%--------------------------------------------------------------------

        \begin{chapterquote}
        Mémoire, j'ai perdu ma mémoire,\\
        suis-je suédois ou finlandais,\\
        je ne m'en souviens pas\dots \\
	(Bosse \"Osterberg)\\ 
        \end{chapterquote}

	\noindent
	Cette section décrit les caractéristiques de la gestion mémoire de Linux, i.e., la mémoire virtuelle et
le tampon cache du disque. Le but, les travaux, ainsi que les choses que l'administrateur système doit prendre en 
considération, sont décrits.
	
\section{Qu'est-ce que la mémoire virtuelle ?}

Linux supporte la \defin{mémoire virtuelle}, c'est à dire l'utilisation d'un disque comme extension de la RAM de
telle sorte que la taille effective de la mémoire utilisable s'accro\^\i t d'autant. Le noyau écrira le contenu d'un
bloc mémoire inutilisé sur le disque dur, ainsi la mémoire peut \^etre utilisée pour autre chose. Quand ce
contenu est à nouveau nécessaire, il est relu en mémoire. Tout ceci se déroule de façon transparente pour 
l'utilisateur ; les programmes s'exécutant sous Linux voient seulement toute la mémoire disponible et ne remarquent
pas que des parties de celle-ci se trouvent sur le disque de temps à autre. Bien s\^ur, lire et écrire sur le
disque dur est plus lent (de l'ordre de mille fois plus lent) qu'en utilisant la mémoire réelle et donc les
programmes ne s'exécutent pas aussi vite. La partie du disque dur utilisée comme mémoire virtuelle est appelée
\defin{espace de swap}.

Linux peut utiliser soit un fichier normal du système de fichiers, soit une partition séparée pour l'espace de
swap. Une partition de swap est plus rapide, mais il est plus facile de changer la taille d'un fichier de swap
(il n'y a pas besoin de repartitionner tout le disque dur et de tout réinstaller). Lorsque l'on sait combien
d'espace de swap est nécessaire, on choisit une partition de swap, mais si l'on n'est pas s\^ur on peut
d'abord utiliser un fichier de swap, utiliser pendant un certain temps le système pour évaluer la taille
nécessaire de l'espace de swap, puis créer une partition de swap lorsqu'on est s\^ur de cette taille.

On doit aussi savoir que Linux permet d'utiliser plusieurs partitions et/ou fichiers de swap en m\^eme temps. Ceci
signifie que si, occasionnellement, on a besoin d'une taille inhabituelle de l'espace de swap, on peut mettre en
place un fichier de swap supplémentaire à de tels moments plut\^ot que de réserver la totalité de cet espace
en permanence.

\section{Création d'une zone de swap}

Un fichier de swap est un fichier ordinaire ; il n'a rien de spécial pour le noyau. La seule chose qui importe pour le
noyau est qu'il n'ait pas de trous, et qu'il soit préparé pour \^etre utilisé avec
\cmd{mkswap}. Cependant, il doit résider sur un disque local, pas sur un système de fichiers monté par NFS, 
ceci pour des raisons d'implantation.

Le point sur les trous est important. Le fichier de swap réserve l'espace disque pour que le noyau puisse
rapidement échanger une page mémoire sans avoir à se soucier de tout ce qui est nécessaire pour allouer un secteur du
disque à un fichier. Le noyau utilise purement et simplement tous les secteurs qui ont été déjà alloués au fichier.
Comme un trou dans un fichier signifie qu'il n'y a pas de secteurs alloués (pour cet emplacement dans le
fichier), il n'est pas bon que le noyau essaie de les utiliser.

Une bonne façon de créer un fichier de swap sans trou est d'utiliser la commande suivante~:
		%
		\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}
		%
	où \fn{/extra-swap} est le nom du fichier de swap et sa taille est donnée après 
	\texttt{count=}.  Il est préférable que la taille soit un multiple de 4 car le noyau écrit des
	\defin{pages mémoires}, qui font 4 Kilo-octets. Si la taille n'est pas un multiple de 4, les derniers
Kilo-octets peuvent \^etre inutilisés.

Une partition n'a rien de spécial non plus. On la crée comme n'importe quelle partition ; la seule différence est
qu'elle est utilisée comme une partition brute, c'est à dire qu'elle ne contiendra pas de système de fichiers. Il
est préférable de marquer les partitions de swap comme étant de type 82 (Linux swap) ; ceci rend le listage des
partitions plus clair, bien que ce ne soit pas strictement nécessaire pour le noyau.

Après avoir créé un fichier ou une partition de swap, il faut écrire une signature à son commencement ; celle-ci 
contient des informations d'administration et est utilisée par le noyau. La commande réalisant cette opération est
\cmd{mkswap}, utilisée de la façon suivante~:
		%
		\begin{tscreen}
\verb|$| {\sl mkswap /extra-swap 1024} \\
\verb|Setting up swapspace, size = 1044480 bytes| \\
\verb|$|
		\end{tscreen}
		%
On notera que l'espace de swap n'est pas encore utilisé~: il existe, mais le noyau ne l'utilise pas pour fournir
de la mémoire virtuelle.
	
On doit \^etre très prudent lorsque l'on utilise \cmd{mkswap}, car la commande ne vérifie pas si le fichier ou
la partition est utilisée pour autre chose. \emph{On peut facilement écraser des fichiers importants et des
partitions avec \cmd{mkswap}!} Heureusement, on a besoin d'utiliser \cmd{mkswap} uniquement lors de l'installation
du système.

Le gestionnaire de mémoire de Linux limite la taille de chaque espace de swap à  127~Mo environ (pour diverses
raisons techniques, la limite réelle est $(4096-10)\times 8\times 4096 = 133890048$ octets, soit
	127,6875 Mo).  Cependant, on peut utiliser jusqu'à 16 espaces de swap simultanément, ce qui donne
un total de presque 2~Go.\footnote{Un Giga-octets par ci, un Giga-octets par là, très bient\^ot nous commencerons
à parler  de mémoire réelle.}

\section{Utilisation d'un espace de swap}

	Une zone de swap initialisée est mise en \oe uvre par \cmd{swapon}.
	Cette commande informe le noyau que l'espace de swap peut \^etre utilisé. Le chemin de l'espace de
swap est donné en paramètre, ainsi, pour lancer les échanges sur un fichier de swap temporaire, on peut utiliser
la commande suivante~:
		%
		\begin{tscreen}
\verb|$| {\sl swapon /extra-swap} \\
\verb|$|
		\end{tscreen}
		%
	Les zones de swap peuvent \^etre automatiquement rendues utilisables en les listant dans le fichier
	\fn{/etc/fstab}.
		%
		\begin{tscreen}
\verb|/dev/hda8        none        swap        sw     0     0| \\
\verb|/swapfile        none        swap        sw     0     0|
		\end{tscreen}
		%
	Les scripts de démarrage lanceront la commande
	\texttt{swapon -a}, qui démarrera l'échange sur toutes les zones de swap répertoriées dans
	\fn{/etc/fstab}.  Ainsi, la commande
	\cmd{swapon} est habituellement utilisée uniquement lorsqu'un espace de swap supplémentaire s'avère
nécessaire.
	
	On peut surveiller l'utilisation des zones de swap gr\^ace à \cmd{free}.
	Elle nous renseigne sur le montant total de l'espace swap utilisé.
		%
		\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 première ligne (\verb|Mem:|) concerne la mémoire physique.
	La colonne << total >>  ne tient pas compte de la mémoire physique utilisée par le noyau qui est, habituellement, 
d'à peu près un Méga-octets. La colonne << used >> donne la mémoire utilisée (la seconde ligne ne tient pas compte 
des tampons). La colonne << free >> donne la mémoire inutilisée. La colonne << shared >> donne la mémoire partagée
par plusieurs processus ; plus il y en a meilleur c'est. La colonne << buffers >> donne la taille du
tampon du cache disque.
	
	La dernière ligne (\verb|Swap:|) donne des informations similaires pour les zones de swap. Si cette
ligne est entièrement à zéro, l'espace de swap n'est pas activé.
	
	Les m\^emes informations sont disponibles en utilisant \cmd{top},
	ou dans le fichier \fn{/proc/info} du système de fichiers \texttt{proc}.
	Il est, pour l'instant, difficile d'obtenir des informations sur l'utilisation d'une zone
de swap spécifique.

	Une zone de swap peut \^etre désactivée gr\^ace à \cmd{swapoff}.
	Habituellement, on n'a pas besoin de le faire, sauf pour des zones de swap temporaires.
	Toutes les pages utilisées dans l'espace de swap sont d'abord rapatriées ; s'il n'y pas suffisamment de
mémoire physique pour les héberger, elles seront alors déplacées (dans un autre espace de swap). S'il n'y a pas
suffisamment de mémoire virtuelle  pour héberger toutes les pages, Linux commencera à se débattre ; après un
long moment, il devrait se rétablir, mais pendant ce temps le système est inutilisable.  Il est préférable
de vérifier (par exemple, avec \cmd{free}) qu'il y a assez de mémoire libre avant de désactiver une zone de
swap.

	Toutes les zones de swap utilisées automatiquement avec
	\texttt{swapon -a} peuvent \^etre désactivées avec \texttt{swapoff -a} ;
	cette commande consulte le fichier \fn{/etc/fstab} pour savoir quoi désactiver. Toutes les zones
de swap activées manuellement reste utilisables.

	Quelques fois, beaucoup d'espace de swap peut \^etre utilisé m\^eme s'il y a beaucoup de mémoire
physique disponible. Ceci peut arriver si, par exemple, à un moment donné il y a besoin de swap mais que plus tard
un gros processus qui utilisait la majeure partie de la mémoire physique se termine et libère celle-ci. Les
données swappées ne sont pas automatiquement rapatriées tant que cela n'est pas nécessaire, ainsi, la mémoire
physique peut rester libre pendant longtemps. On n'a pas à se soucier de cela, mais il peut \^etre intéressant de
savoir ce qui se passe.

\section{Partage des zones de swap avec d'autres systèmes d'exploitation}

	La mémoire virtuelle est intégrée dans de nombreux systèmes d'exploitation. Comme ils n'en ont besoin
que lorsqu'ils tournent, i.e., jamais au m\^eme moment, les espaces de swap de tous les systèmes sauf de celui 
en cours d'utilisation sont gaspillés. Il serait plus efficace de leur faire partager un unique espace de swap.
Ceci est possible, mais peut nécessiter un peu de bricolage. Le Tips-HOWTO contient quelques indications sur
la façon d'implanter ça.

\section{Allocation de l'espace de swap} \label{sec:swap-alloc}

	Certains diront que l'on doit réserver pour le swap deux fois la taille de sa mémoire physique, mais
c'est une règle bidon. Voici comment faire ça proprement~:

    \begin{enumerate}

    \item

	On estime la mémoire totale dont on a besoin. C'est la plus grande taille de mémoire dont on aura besoin
à un moment donné, c'est à dire la somme de la mémoire nécessaire pour tous les programmes que l'on veut lancer en
m\^eme temps. Le calcul peut \^etre fait en lançant tous ces programmes au m\^eme moment.

	Par exemple, si on veut lancer X, on doit lui réserver à peu près 8~Mo, gcc nécessite plusieurs Mo
(quelques fichiers nécessitent un montant inha\-bi\-tu\-el\-le\-ment gros, jusqu'à des dizaines de Mo, mais en
général 4  suffisent), etc. Le noyau utilisera à peu près un Mo et les shells usuels et autres petits
utilitaires peut \^etre une centaine de Ko (disons un Mo pour le tout). On n'a pas besoin d'\^etre exact, 
des estimations grossières suffisent mais on peut vouloir \^etre pessimiste.
	
	On se rappellera que si plusieurs personnes doivent utiliser le système en m\^eme temps, ils
consommeront tous de la mémoire. Cependant, si deux utilisateurs exécutent le m\^eme programme au m\^eme moment,
le total de la mémoire con\-som\-mée n'est généralement pas le double car les pages de code et les biblio\-thè\-ques
partagées n'existent qu'en un seul exemplaire.
	
	Les commandes \cmd{free} et \cmd{ps} sont utiles pour estimer les besoins en mémoire.

    \item

	On ajoute une marge de sécurité par rapport à l'estimation de l'étape 1. Ceci est d\^u au fait que
les estimations des tailles des programmes sont probablement fausses car on aura s\^urement oublié quelques 
programmes ; ainsi, on est s\^ur que l'on aura de l'espace supplémentaire juste au cas où. Quelques Mo feront
l'affaire. (Il est préférable de réserver trop plut\^ot que pas assez d'espace de swap, mais il ne faut
pas trop en faire et réserver tout le disque car l'espace de swap inutilisé est un espace gaspillé ; voir plus
loin comment ajouter plus de swap). De plus, comme il est plus agréable de travailler avec des nombres ronds, on
peut arrondir la valeur au Mo supérieur.
	
    \item

	En fonction des calculs ci-dessus, on sait la mémoire totale dont on a besoin. Donc, pour réserver 
l'espace de swap, on n'a plus qu'à soustraire la taille de la mémoire physique de la taille totale pour conna\^\i tre
la taille de l'espace de swap nécessaire. (Sur certaines versions d'UNIX, on doit allouer l'espace aussi pour une
image de la mémoire physique, par conséquent on utilise la quantité calculée à l'étape 2 et on ne fait pas
la soustraction).

    \item

	Si l'espace de swap calculé est beaucoup plus grand que la mémoire physique (plus que deux fois plus grand),
il est préférable d'investir dans de la mémoire, sinon les performances seront trop faibles.

    \end{enumerate}
    
	Il est souhaitable d'avoir au moins un peu d'espace de swap, m\^eme si les calculs indiquent qu'il n'y en n'a
pas besoin. Linux utilise l'espace de swap de façon intensive afin de libérer le maximum de mémoire physique. Linux
échangera les pages mémoires qui n'ont pas été utilisées m\^eme si la mémoire n'est pas encore demandée par autre
chose. Ceci évite d'attendre cet échange quand il sera nécessaire --~l'échange peut \^etre fait plus
t\^ot, lorsque le disque est au repos.

L'espace de swap peut \^etre divisé entre plusieurs disques. Ceci peut quelques fois accro\^\i tre les
performances selon les vitesses relatives des disques et les méthodes d'accès de ceux-ci. On doit tester plusieurs
combinaisons, mais réaliser ces expériences est plut\^ot difficile et il ne faut pas croire qu'une configuration 
donnée est meilleure qu'une autre car ce n'est pas toujours vrai.

\section{Le tampon cache}
\label{sec:buffer-cache}

	Lire à partir d'un disque\footnote{Sauf, évidemment, un disque RAM} est très lent comparé à un accès
à la mémoire physique. De plus, il est fréquent de lire la m\^eme partie du disque plusieurs fois pendant des
périodes relativement courtes. Par exemple, on peut d'abord lire un message e-mail, puis lire la lettre dans
un éditeur lorsqu'on lui répond et ensuite refaire lire cette lettre par le programme de mail lorsqu'il
la copie dans un dossier. Considérons aussi le nombre de fois où la commande \cmd{ls} peut \^etre lancée sur 
un système avec beaucoup d'utilisateurs. En lisant l'information sur le disque seulement une fois, on peut
accélérer toutes les lectures, sauf la première. Ceci est appelé \defin{cachage du disque}, et la mémoire
utilisée pour cela est appelée \defin{tampon cache}.

Comme, malheureusement, la mémoire est une ressource finie, voire rare, le tampon cache ne peut généralement pas 
\^etre assez gros (il ne peut contenir toutes les données dont on a besoin). Lorsque le cache est plein, les
données inutilisées les plus anciennes sont retirées ce qui libère de la place pour de nouvelles données.

Le cachage du disque fonctionne aussi pour les écritures. D'un c\^oté, une donnée qui est écrite est
souvent relue (par exemple, un fichier de code source est sauvé dans un fichier, puis relu par le compilateur), 
et donc mettre la donnée qui est écrite dans le cache est une bonne idée. D'un autre c\^oté, en mettant
uniquement la donnée dans le cache et en ne l'écrivant pas sur le disque tout de suite, le programme qui
écrit va plus vite. Les écritures peuvent alors \^etre faites en arrière-plan, sans ralentir les autres programmes.

La plupart des systèmes d'exploitation utilisent les tampons caches (bien qu'ils puissent \^etre appelés autrement),
mais ils ne fonctionnent pas tous selon les principes décrits ci-dessus. Certains sont \defin{write-through}~: les
données sont écrites sur le disque immédiatement (elles sont aussi gardées dans le cache, bien s\^ur). Le cache
est dit \defin{write-back} si les écritures sont faites plus tard. Cette dernière méthode est plus efficace que
la première, mais est aussi plus sujette aux erreurs~: si la machine se plante, ou si l'alimentation est coupée
au mauvais moment, ou si la disquette est ôtée du lecteur avant que les données du cache en attente d'écriture aient
été écrites, les changements dans le cache sont en général perdus. Ceci peut m\^eme signifier que le système
de fichiers (s'il y en a un) n'est pas en état de marche, peut \^etre parce que les données non écrites comprenaient
des modifications importantes des informations de gestion de celui-ci.
	
	Pour cette raison, on ne doit jamais couper l'alimentation sans utiliser une pro\-cé\-dure d'arr\^et 
appropriée (voir le chapitre~\ref{ch:boothalt}), ou ôter une disquette du lecteur tant qu'elle n'a pas été démontée (si elle
était montée). De la m\^eme façon, on doit attendre qu'un programme quel qu'il soit et qui l'utilisait ait signalé qu'il s'était terminé et que
la diode du lecteur ne soit plus allumée. La commande \cmd{sync} \defin{vide} le tampon, i.e, force toutes les
données non écrites à \^etre transférées sur le disque, elle peut \^etre utilisée lorsqu'on veut \^etre s\^ur que
tout ait été correctement écrit. Dans les systèmes UNIX traditionnels, il existe un programme appelé
\cmd{update} qui s'exécute en arrière-plan et qui réalise un \cmd{sync} toutes les 30~secondes, il n'est donc
généralement pas nécessaire d'utiliser \cmd{sync}. Linux possède un démon supplémentaire, 
\cmd{bdflush}, qui réalise une synchronisation moins parfaite plus souvent afin d'éviter les blocages dus aux
importants échanges avec le disque que \cmd{sync} cause quelquefois.
	
Sous Linux, \cmd{bdflush} est lancé par \cmd{update}.  Normalement, il n'y a pas à s'en occuper, mais si
\cmd{bdflush} meurt pour une raison quelconque, le noyau préviendra et on pourra le relancer manuellement 
(\cmd{/sbin/update}).

Le tampon ne cache pas les fichiers mais les blocs, qui sont les plus petites unités d'échange avec le disque
(sous Linux, ils font généralement 1~Ko). De cette façon, les répertoires, les super-blocs et les données de 
gestion du système de fichiers ainsi que les disques sans systèmes de fichiers sont aussi cachés.

L'efficacité d'un cache est d'abord décidée par sa taille. Un petit cache est presque inutile~: il contiendrait
si peu de données que toutes les données cachées seraient vidées du cache avant d'\^etre réutilisées. La taille
critique dépend du nombre de données lues et écrites, ainsi que du nombre de fois où la m\^eme donnée est
accédée. La seule façon de savoir est de faire des essais.

Si le cache a une taille fixe, il n'est pas très bon qu'il soit trop gros, car cela peut réduire la mémoire disponible et
provoquer du swapping (ce qui ralentit). Pour utiliser le plus efficacement possible la mémoire réelle, Linux utilise
automatiquement tout la mémoire RAM disponible pour le cache, mais réduit aussi automatiquement la taille du 
cache quand les programmes ont besoin de plus de mémoire.

Sous Linux, on n'a rien à faire pour utiliser le cache, tout se passe automatiquement. Mis à part suivre les
procédures correctes d'arr\^et 	et d'éjection des disquettes, on n'a pas à s'en soucier.
