Explications sur l'adressage et la RAM : sont-elles correctes ?

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous,

Je souhaite prendre de l'avance sur ma troisième année d'info et pour ce faire je révise actuellement tout ce qui est mémoire primaire ("mécanisme d'adressage", "pagination", "segmentation" et "mémoire d'un processus UNIX" - termes issus du programme de ma fac).

Du coup je cherche des cours sur Internet, des vidéos d'explications, je pose des questions sur des forums, etc. etc. Et pour m'assurer que ce que j'apprends est correct, j'aimerais que vous me donniez votre avis, si possible, sur le "mini-tuto" qui suit, s'il vous plaît.

SOMMAIRE

PARTIE 1. Mécanismes d'adressage

-> Enjeux et raison d'être des mécanismes d'adressage

-> Deux mécanismes d'adressage

->-> Définition : un Registre

->-> Premier mécanisme : le Fence-register, ou "Registre-barrière"

->-> Second mécanisme : le Base-register (Registre de base)

->-> Qui fait usage de ces mécanismes d'adressage ?

PARTIE 2. Mémoire d'un processus UNIX dans le cas d'une mémoire contiguë.

-> Mémoire contiguë et mémoire non-contiguë

-> Définition de "mise en mémoire d'un processus UNIX"

-> Trois algorithmes de mise en mémoire des processus

-> Compactage (défragmentation)

Bientôt : Mémoire virtuelle (pagination, segmentation et mémoire d'un processus UNIX dans le cas d'une mémoire virtuelle, donc non-contiguë)… :)

PARTIE 1. Mécanismes d'adressage

Enjeux et raison d'être des mécanismes d'adressage

Pour parler de ces mécanismes, il faut d'abord définir la RAM. Elle est représentable par un tableau à une dimension. Il est indexé et l'index utilisé est une adresse (de valeur 0 à FFFFF). Une case de ce tableau s'appelle un mot.

Toute donnée peut être stockée dans la RAM : les processus en exécution, des valeurs, des adresses, etc.

Le moniteur est la partie du noyau qui s'occupe des adressages voulus par l'OS. Il est stocké en début de RAM (à partir de l'adresse physique - donc pas logique - 0). Le moniteur peut accéder à n'importe quel mot de la RAM.

Quand on écrit un programme, on va chercher à accéder à la RAM, en écriture notamment. Il faut donc protéger les premiers mots de la RAM puisqu'il y a le moniteur du noyau dedans. On ne peut donc pas allouer n'importe comment : des mécanismes d'adressage ont été inventés pour protéger le moniteur du noyau.

Deux mécanismes d'adressage

Définition : un Registre

Avant d'aller plus loin, il faut expliquer ce qu'est un registre : c'est une petite unité de stockage :).

Premier mécanisme : le Fence-register, ou "Registre-barrière"

Mettons qu'un programmeur veuille allouer une adresse de la RAM. Comme on l'a dit précédemment, il ne faut pas qu'il n'interfère avec le moniteur du noyau. Voici le concept de ce mécanisme :

  1. Lors de la fabrication de la machine, on inscrit dans un registre la valeur qui correspond à l'adresse où le stockage du moniteur est enfin complet. Le registre ainsi utilisé est appelé le "fence register" et a donné son nom au mécanisme.

  2. Après la fabrication de la machine, et le démarrage de celle-ci, toute tentative d'allocation d'une adresse de la RAM suit le chemin suivant : si l'adresse qu'on souhaite allouer est plus petite ou égale à la valeur du fence register, alors l'allocation est interdite et une interruption est émise : on n'a pas le droit d'accéder en écriture (de modifier) ou de lire les mots de la RAM utilisés par le moniteur du noyau. Sinon, tout va bien, tout est OK.

Ce mécanisme possède 3 inconvénients :

  1. Il nécessite que toute, absolument toute, tentative d'allocation passe par cette vérification (du coup c'est pas rapide) ;
  2. Si on veut protéger non seulement le moniteur du noyau mais également d'autres mots (contigüs aux mots du moniteur), c'est difficile car la valeur du fence register est souvent fixe ;
  3. Le programmeur ne va pas pouvoir utiliser des adresses dans la plage [0;FFF] mais seulement dans ]valeur_fence_register;FFF] et ce n'est pas du tout pratique pour lui.

Pour régler l'inconvénient n°3, on a inventé un nouveau mécanisme d'adressage : le base register.

Second mécanisme : le Base-register (Registre de base)

Ce mécanisme redonne au programmeur la possibilité d'allouer des adresses de la RAM dans la plage [0;FFF], ce qui n'est pas permis par un fence-register.

Explications du mécanisme.

  1. Au lieu d'avoir un fence-register, on a un base-register. Le base-register contient la même valeur que le fence-register (à savoir "l'adresse où le stockage du moniteur est enfin complet").

  2. Mais ici, aucune comparaison mathématique n'a lieu contrairement au fence-register. Au lieu de ça, on procède à une addition : adresse_tentative_allocation + valeur_base_register.

  3. Le résultat de cette opération est une adresse qui est forcément plus grande que celle du mot de la fin du stockage du moniteur. Le programmeur peut ainsi allouer des adresses commençant par 000 (incluse) sans pouvoir accéder au moniteur. Aucune interférence programmeur-moniteur n'est donc possible.

Ce mécanisme a l'avantage que le programmeur n'a pas besoin de connaître la valeur du base-register (il le devait dans le cas du fence-register). Tout est transparent pour lui.

Qui fait usage de ces mécanismes d'adressage ?

L'OS (le moniteur du noyau de l'OS plus précisément). C'est l'OS qui s'occupe de toute la gestion de la RAM. Ainsi le programmeur n'a pas besoin d'y penser.

Fin de la partie "Mécanismes d'adressage".

PARTIE 2. Mémoire d'un processus UNIX dans le cas d'une mémoire contiguë.

Mémoire contiguë et mémoire non-contiguë

Avant d'aller plus loin, il nous faut définir les termes "mémoire contiguë" et "mémoire non-contiguë".

Mémoire contiguë : désigne une RAM que seul un OS qui n'est pas en temps-partagé (donc pas multi-tâches) peut utiliser. C'est-à-dire que les processus qui y sont stockés lors de leur exécution ne peuvent pas y être présents par petits bouts, par parties : ils y sont présents en entier, chacun.

Mémoire non-contiguë : cette RAM peut être utilisée par un OS qui est ou n'est pas en temps-partagé (donc qui est ou n'est pas multi-tâches). C'est-à-dire que les processus qui y sont stockés lors de leur exécution peuvent être découpés en parties, et ces parties sont stockées en RAM à des mots différents. Les mots les contenant peuvent être précédés ou suivis par des mots contenant des parties d'autres processus.

Cette partie ne traite de la mémoire des processus UNIX que dans le cadre d'une mémoire contiguë.

Définition de "mise en mémoire d'un processus UNIX"

Lors de son exécution, un processus est stocké dans la RAM (autrement dit : ses données, à savoir ses instructions Assembleur et autres). Si sa taille fait pile-poil la taille d'un mot, alors ce mot est bien évidemment totalement rempli par le processus. Si sa taille est plus petite que la taille d'un mot, alors ce mot n'est pas totalement rempli, évidemment. Si sa taille est plus grande que la taille d'un mot, au moins un mot sera totalement rempli, autant de mots que nécessaires seront totalement, et un mot au plus ne sera pas totalement rempli.

Comme diverses données sont stockées dans la RAM, il peut arriver que celle-ci ne présente pas assez de place pour accueillir un processus. Même si une RAM donnée présente plusieurs mots vides, tous plus petits que la taille d'un processus donné, mais qui pourtant font la aille de ce dernier quand on les cumule, le processus dont nous parlons ne pourra y être stocké car nous sommes dans le cas d'une mémoire contiguë et il est impossible de dispatcher un processus en parties.

Ainsi donc, si la RAM ne présente pas assez de place pour accueillir un processus, alors ce dernier n'est pas mis en mémoire, mais il est mis en attente de mise en mémoire.

Trois algorithmes de mise en mémoire des processus

Note : le terme "bloc" désigne "ensemble de mots (vides) dont la cardinalité est supérieure ou égale à 1".

Pour mettre en RAM un processus, l'OS (le moniteur du noyau) implémente l'un des algorithmes suivants (le premier est le meilleur en terme de rapidité, le second est moins bon et le troisième est à éviter).

  1. Algorithme "First-fit" : Le premier bloc suffisamment grand pour contenir le processus ;
  2. Algorithme "Best-fit" : Le plus petit bloc suffisamment grand pour contenir le processus ;
  3. Algorithme "Worst-fit" : Le plus grand bloc suffisamment grand pour contenir le processus.

Compactage (défragmentation)

Ce concept consiste à optimiser la gestion de la mise en mémoire des processus UNIX.

On déplace les processus en mémoire de façon à rendre contigus les mots vides (c'est plus propre et c'est mieux :)).

Bientôt : Mémoire virtuelle (pagination, segmentation et mémoire d'un processus UNIX dans le cas d'une mémoire virtuelle, donc non-contiguë)…

+0 -0

Bon, j'ai un peu plus de temps, je vais pouvoir faire plaisir aux rageux du message précédent.

Le principal défaut de ce tuto, c'est qu'il n'y a aucune contextualisation. L'adressage de la mémoire dépend énormément du processeur avec lequel on travaille : le même emplacement mémoire ne sera pas du tout adressé de la même manière sur un processeur x86 et sur un processeur ARM. Et même au sein d'un même processeur, chaque mode de fonctionnement peut avoir ses particularités : ceux qui ont déjà eu à passer du mode réel au mode protégé savent de quoi je parle.

Et par dessus cela, il y a l'abstraction que font les systèmes d'exploitation pour avoir (autant que possible) une représentation unique de toutes les formes de mémoire : si le noyau Linux autorise un de vos programmes à utiliser un bloc de mémoire dans la RAM de votre carte graphique, rien dans l'adresse ne vous permettra de le distinguer d'un bloc de mémoire dans la RAM de la carte-mère.

Ici… ben rien. On n'a aucune idée du modèle de processeur, du mode de fonctionnement, de si l'on est ou non au sein d'un OS. Il est question de processus UNIX, ce qui laisse supposer au moins le mode protégé (à supposer qu'on soit sur un x86(_64)), mais la première section dit « Il est indexé et l'index utilisé est une adresse (de valeur 0 à FFFFF) », lesquelles bornes sont celles du mode réel. Ah oui, mais le dernier titre annonce comme encore à venir « Mémoire virtuelle (pagination, segmentation » : bah merde ! La segmentation, même en mode réel on ne peut pas y échapper. Alors on est où, là, exactement ? >_<

Ajoute à cela des imprécisions assez sévères, comme « Avant d'aller plus loin, il faut expliquer ce qu'est un registre : c'est une petite unité de stockage :). » par exemple. Super ! Un emplacement dans la RAM, c'est aussi une petite unité de stockage. Une CMOS RAM aussi. Ce qui qualifie un registre, c'est que c'est une mémoire interne au processeur. Ce qui nous ramène à l'importance d'expliquer avec quel matériel on travaille, car chaque processeur a son propre jeu de registres, même s'il y a des tendances communes.

Pis y'a des passages qui m'ont fait dire « Waat ?! », du genre de celui-là : « Le moniteur est la partie du noyau qui s'occupe des adressages voulus par l'OS. Il est stocké en début de RAM (à partir de l'adresse physique - donc pas logique - 0). ». À l'adresse physique 0 de ma RAM, y'a le tableau de vecteurs d'interruption (IVT en anglais) de mon BIOS qui attend sagement là un éventuel retour en mode réel, et c'est le cas sur tous les Linux.

Bref, même si tu arrives à piger quelque chose à ses explications, tu as plus de chance d'apprendre des conneries que quelque chose d'utile.

+3 -0

Dominus Carnufex, merci pour ces explications, tu as l'air de t'y connaître ! Je pense que les tutos que j'ai lus expliquent juste les notions fondamentales sans trop rentrer dans les détails, ce qui expliquerait pourquoi ils ne font pas mention des modes protégé/réel, du type de processeur, des différents types de RAM, etc. Même si ces infos sont apparemment importantes si l'on veut faire preuve de rigueur.

Ces notions fondamentales, ici, sont les différents mécanismes d'adressage (fence-register, base-register) et la mise en mémoire d'un processus. Est-ce que ces concepts ont été expliqués correctement ?

+0 -0

Ben non. C'est pas juste une question de rigueur, c'est une question de ne pas apprendre n'importe quoi. Le fence register et le base register ne sont pas des « mécanismes d'adressage », ce sont des solutions techniques au problème du partage de la mémoire. Je vais détailler un peu, que ce soit plus clair.

La RAM, fondamentalement, c'est un composant électronique, avec lequel tu ne communiqueras jamais directement, mais toujours par l'intermédiaire d'un processeur. Et ce processeur peut avoir un ou plusieurs mécanismes d'adressage, c'est-à-dire moyens de donner un nom à différentes partie de la mémoire physique disponible dans le composant électronique RAM. Le tuto ci-dessus n'aborde à aucun moment ce sujet.

Maintenant, une fois que cette mémoire est mise à disposition de tes programmes par le biais du processeur, émerge très vite un problème : comment faire en sorte que le système d'exploitation, qui doit garder le pouvoir face aux autres programmes, ne se fasse pas écrire sur la tronche par un programme indélicat qui serait venu empiéter sur son espace en mémoire ?

La solution technique à ce problème la plus basique qui soit, c'est la clôture (fencing) : le processeur interdit que des programmes situés au-delà d'une certaine adresse (selon le système d'adressage que lui a défini, on est bien d'accord) touchent à la mémoire située en deçà de cette adresse. Elle peut être rendue un peu plus souple en autorisant le système d'exploitation à déplacer la barrière, l'adresse de celle-ci étant conservé dans un registre (le fameux fence register) pour des raisons de commodité : comme cette adresse est utilisée à chaque opération sur la mémoire, autant qu'elle soit dans un emplacement mémoire accessible très rapidement.

Cette solution technique est à peu près valable avec un système d'exploitation monotâche, qui ne sait gérer qu'un seul programme à la fois. Elle rencontre ses limites dès lors que l'on veut permettre à plusieurs programmes d'utiliser la mémoire, car elle n'empêche absolument pas un programme de piétiner la mémoire d'un autre programme.

Une solution technique à ce nouveau problème, c'est le système dit base-bound. Chaque programme se voit attribuer une adresse de base en deçà de laquelle il ne peut accéder, et une adresse plafond qu'il n'a pas le droit de dépasser. Pour des raisons d'économie, on utilise le système décrit dans le tuto qui consiste à additionner l'adresse donnée dans le programme à l'adresse de base pour avoir l'adresse « réelle ».

Maintenant, cela étant dit, il y a un point essentiel que le tuto ne précise absolument pas : ces solutions techniques sont antédiluviennes. N'importe quel système d'exploitation moderne utilise des techniques bien plus puissantes pour virtualiser la mémoire, développe son propre mécanisme d'adressage, et relègue ce genre de considérations aux oubliettes. Pour qu'un système d'exploitation ait besoin de recourir à des solutions comme le fencing, c'est que le processeur lui-même ne propose pas de solutions plus adaptée, et la gestion de différents niveaux de privilège directement par le processeur, ça remonte au moins au mode protégé des processeurs x86, introduit en 1982.

Autant dire qu'en parlant de fence register, il n'aborde pas une notion fondamentale, il fait de l'archéologie mais sans te le dire. Et en plus, il le fait mal, en n'expliquant pas ce que c'est réellement…

Quant à la partie sur le chargement de processus en mémoire… Pffff… :(

Cette partie ne traite de la mémoire des processus UNIX que dans le cadre d'une mémoire contiguë.

Ce qui selon sa définition signifie dans le cadre d'un OS monotâche. Sauf que si l'OS est monotâche, alors il n'y a qu'un seul processus à la fois en mémoire, qui peut donc s'étaler sur toute la mémoire allouée à l'espace utilisateur, la question de lui trouver de la place ne se pose même pas. Mais poursuivons, en faisant semblant qu'il ait voulu dire « multitâche ».

Lors de son exécution, un processus est stocké dans la RAM (autrement dit : ses données, à savoir ses instructions Assembleur et autres). Si sa taille fait pile-poil la taille d'un mot, alors ce mot est bien évidemment totalement rempli par le processus. Si sa taille est plus petite que la taille d'un mot, alors ce mot n'est pas totalement rempli, évidemment. Si sa taille est plus grande que la taille d'un mot, au moins un mot sera totalement rempli, autant de mots que nécessaires seront totalement, et un mot au plus ne sera pas totalement rempli.

Wut ? o_O Je sais pas ce qu'il entend par « mot », mais ce n'est clairement pas la même chose que nous autres pauvres mortels. Un mot, quand on parle de mémoire, c'est un multiple de la plus petite zone de mémoire qui puisse avoir une adresse individuelle (généralement un octet) : par exemple, sur les processeurs x86, un mot fait 2 octets. Alors évidemment qu'un processus va prendre plus qu'un mot en mémoire…

Je ne m'appesantis pas sur le reste de l'explication, l'absence de contexte y devient vraiment gênante. Par exemple, ses explications ne disent pas si l'OS étudié utilise ou non les possibilités de segmentation / pagination du processeur, ni s'il fait usage d'un modèle particulier d'organisation des données de l'exécutable en mémoire1, ni s'il offre la possibilité de faire appel à des bibliothèques partagées, des zones de mémoire communes à plusieurs processus, des relations de dépendance entre processus, etc. Toutes choses qui influent sur la manière de gérer la mise en mémoire de tout ça.


  1. Par exemple, les vieux Windows simulaient un MS-DOS en mode réel, avec une IVT, un BIOS, quelques données annexes pré-chargées et le programme qui a grosso modo les mains libres sur tout son mébioctet de mémoire. D'autres système séparent les instructions exécutables d'une zone mémoire où le tas occupe de plus en plus de place en partant du bas et la pile de plus en plus de place en partant du haut, jusqu'à se rejoindre, mais sans jamais pouvoir marcher sur les instructions exécutables. 

+2 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte