La gestion de la mémoire est un des aspects complexes de l'informatique. De nos jours, les gens croient (injustement) que la protection de mémoire est le remède miracle de tous les maux et qu'elle rend les ordinateurs plus stables. En vérité ce n'est qu'UNE variable (cependant importante) d'une équation complexe.
Cet article devrait vous aider à comprendre ce que sont les différents types de protection de mémoire et comment (pourquoi) ils fonctionnent.
Un ordinateur est équipé de RAM (mémoire temporaire) qui est utilisée pour emmagasiner des programmes et vos données pendant que vous travaillez. Le système d'exploitation (OS) fonctionne en tout temps, ainsi que, peut être, plusieurs autres applications -- ils doivent tous occuper des zones différentes dans la RAM. Le problème c'est que les applications mal conçues peuvent non seulement empiéter sur elles-mêmes -- mais également sur les autres applications, ou même les systèmes d'exploitation.
La mémoire n'est qu'une très longue série d'adresses (emplacements) qui renferment des valeurs (du code ou des données), pour un total de 4 GB (giga-octets). La plupart des représentations des zones de mémoire sont à deux dimensions.
Voici une cartographie simplifiée de la mémoire ne montrant que les applications et le système d'exploitation --
Remarquez que la majorité de la mémoire est constituée d'espace libre. La RAM est utilisée pour les applications et le système d'exploitation, il y a toujours beaucoup d'espace libre.
Si la taille de la mémoire est habituellement de 4 GB (mémoire adressable) et que vous possédez 32 MB de mémoire RAM physique (réelle) et le double en utilisant la mémoire virtuelle, pour un total de 64 MB -- vous n'utilisez que 1.6% de tout l'espace mémoire adressable. Si vous aviez à choisir un emplacement de mémoire au hasard, il y aurait 98.4% de chance que vous tombiez sur un espace mémoire vide. Les chances sont encore plus grandes si on considère que les programmes n'utilisent habituellement PAS toute la RAM disponible (il y a des tas d'emplacements libres entre les applications). Il y a donc peu de chances pour que, au hasard, vous empiétiez sur quelque chose possédant une valeur -- et cela pour chacune des erreurs commises. Cependant, les ordinateurs sont très rapides -- alors les erreurs peuvent débouler en de rapides successions. De plus, la majorité des erreurs ne sont PAS le fruit du hasard. L'erreur se produit souvent à des endroits prévisibles -- ce constat est très important car la capacité de prédire l'endroit où se produira une erreur vous permettra d'attraper 90% des erreurs en ne protégeant que quelques emplacements de mémoire -- mais plus à ce sujet plus tard.
Alors quels sont les différents types de protection de mémoire ?
Imaginez que App1 (l'application #1) commet une erreur, et qu'au lieu d'effectuer une modification à l'intérieur d'elle-même, elle fait une modification dans App2 (ou encore dans le système d'exploitation) (1). On gâche ainsi la mémoire d'un autre et cela provoquera éventuellement le plantage de App2 (ou du système d'exploitation), causé parce cette modification «non autorisée». Une autre erreur commune est celle où App2 dépasse ses propres limites et empiète sur App3 -- causant le plantage de App3 (et probablement App2).
(1) Rappelez-vous, la mémoire n'est qu'un grand vecteur d'adresses -- ainsi une simple erreur mathématique ou (plus communément) l'oubli de nettoyer quelque chose (l'initialisation d'un emplacement) avant de l'utiliser, peut résulter en une «mauvaise adresse».Imaginez que chaque fois que vous composez le mauvais numéro de téléphone (ou que vous commettez une erreur dans l'inscription d'une adresse sur une lettre) cela fait exploser la maison du destinataire! Boom!
Les programmeurs doivent travailler avec des centaines ou des milliers d'adresses, une erreur dans le calcul d'une seule de ces adresses est souvent fatale!
La protection de la mémoire protège contre ces erreurs de programmeurs. Chaque application ne peut modifier que SA propre mémoire. Aussitôt qu'une application écrit (ou lit) à l'extérieur de ses limites, le système d'exploitation fait planter (ou quitter) immédiatement l'application commettant l'erreur. Ce qui signifie que l'utilisateur perd toutes les données sur lesquelles ils travaillaient à ce moment là -- mais au moins cette application a été empêchée d'écrire de fausses données ou de mettre en danger d'autres applications et le système d'exploitation. Il en résulte plus de stabilité dans le système d'exploitation, et les applications sont protégées entre elles -- cependant ces applications plantent plus souvent (ou quittent inopinément). Si vous avez déjà vu une application quitter sans raison (avec une erreur système quelconque), alors c'est probablement le résultat du travail de la protection de mémoire.
Certaines techniques de protection de mémoire protègent non seulement les applications entre elles, mais également les applications contre elles-mêmes.
Une application possède plusieurs régions différentes à l'intérieur de sa propre zone de mémoire qui peuvent être utilisées pour emmagasiner différentes choses. L'application a son code (les instructions dictant à l'ordinateur quoi faire) et ses données (l'information, une copie du fichier en mémoire et d'autres zones temporaires). Les données sont réparties entre la pile (les variables) et le heap (les structures que le programmeur créées -- habituellement les parties du fichier qui résident en mémoire).

Collision entre la pile et le heap: la pile s'agrandit en direction du heap (et vice-versa), s'ils se rencontrent alors l'application est à court de mémoire. Si le programmeur n'y porte pas attention, un de ceux-là (pile ou heap) empiétera sur l'autre. Lorsque l'application se marche sur les pieds, ce n'est qu'une question de temps avant qu'elle ne plante. La détection de collision entre la pile et le heap est excellente pour le système d'exploitation, ce qui permet au programme de terminer «gracieusement» et rapidement (avant qu'il n'est le temps d'endommager ses propres données), plutôt que de permettre au programme de continuer à tourner et ainsi endommager les fichiers de données ou encore de faire planter le système d'exploitation.
Code en lecture seulement: puisque votre code (le programme) ne sera qu'exécuté et que vos données sont supposées être emmagasinées ailleurs (dans la pile ou le heap) -- un bon système d'exploitation garantira qu'un programme ne pourra jamais écrire dans son propre espace de code (ou dans celui des autres applications). Sinon une simple erreur mathématique peut permettre à un programme d'altérer son propre code -- ce qui fera tôt ou tard planter l'application.
NOTE: La protection du code (code en lecture seulement) ne peut être mise de l'avant si les programmeurs utilisent une mauvaise technique de programmation appelée code auto-modifiant (ce qui veut dire que les programmes se modifient eux-mêmes pendant qu'ils s'exécutent).
Le système d'exploitation n'est qu'un programme très complexe avec lequel les autres programmes coopèrent et travaillent. Vu son importance, on fait beaucoup pour le mettre à l'abri des autres applications et de lui-même.
Le système d'exploitation est divisé en plusieurs parties -- ainsi en protégeant ces parties les unes contre les autres (et des autres applications), il peut être rendu plus stable. Les parties qui sont à la base du système d'exploitation sont: le noyau du système (Kernel), les pilotes de dispositifs (Drivers) et les services.

Noyau: c'est le surveillant (appelé également Kernel) qui accorde de la mémoire aux autres, expédie des messages et qui joue le policier de la circulation (prévient les collisions).
Pilotes de dispositifs (Drivers): ce sont des petits programmes conçus pour contrôler un périphérique ou un autre dispositif de quincaillerie. Les cartes vidéo, imprimantes, numériseurs, joysticks, microphones, haut-parleur, etc. possèdent tous des pilotes de dispositifs. Plusieurs sont livrés avec le système d'exploitation, d'autres doivent être ajoutés (avec les pièces de quincaillerie que vous achetez).
Services: ce sont de grosses librairies et des fonctions à l'intérieur du système d'exploitation qui permettent aux programmeurs de réaliser des choses. Elles peuvent manipuler des polices de caractères, afficher des fenêtres, ou manipuler des graphiques.
NOTE: Le pilote de la carte vidéo s'occupe d'envoyer les commandes qui partent et arrivent à la carte vidéo (fonctions de bas niveau) -- mais les services graphiques sont des fonctions de plus haut niveau tels que l'affichage de lignes, d'images, etc.
Si l'ensemble des services du système d'exploitation (pilotes et services) doit passer par le Kernel pour envoyer des messages ou pour accéder à la mémoire (autre que celle leur appartenant), alors le Kernel est appelé MicroKernel. (Micro pour petit, Kernel pour noyau central). Cette architecture MicroKernel protège les parties du système d'exploitation les unes contre les autres et permet à ce code de demeurer le plus petit et le plus efficace possible.
Si les parties (pilotes et applications) du système d'exploitation ne sont pas protégées les unes contre les autres et ont la possibilité d'envoyer des messages aux applications (ou entre elles) directement, ou qu'ils ont la possibilité d'accéder à la mémoire des autres directement, alors le système est considéré être un système monolithique (un ensemble unique).
NOTE: WinNT n'est pas un MicroKernel, Rhapsody et le MacOS 9 peuvent utiliser le Mach MicroKernel (pour la version des développeurs, Rhapsody utilise Mach2.x qui n'est pas un MicroKernel -- les versions subséquentes utiliseront le Mach version 3.0 qui est un MicroKernel).
Compromis: Certaines parties du système d'exploitation peuvent bénéficier de plus de vitesse (légèrement) s'ils n'ont pas à subir le système policier de surveillance joué par le MicroKernel -- cependant il devient plus difficile d'assurer la stabilité du système. Les pilotes de dispositifs (de tierces-parties ou non) peuvent également bénéficier de plus de vitesse (sans le MicroKernel) s'ils peuvent accéder directement à la mémoire et envoyer des messages -- mais ici aussi, le coût est un risque plus élevé. L'équation performance-robustesse est beaucoup plus une question de qualité de code des pilotes de dispositifs (et de tests), qu'à savoir si c'est un MicroKernel ou non. Il y a beaucoup de conflits entre les ingénieurs concernant ce choix de conception. Également, peu de systèmes d'exploitation sont «purs» et chacun utilise des compromis.
Rappelez-vous que vos applications sont aussi fragiles que le système d'exploitation et les pilotes de dispositifs que vous installez peuvent l'être. La protection de mémoire n'est pas un remède contre les logiciels et pilotes de dispositifs de mauvaise qualité. Alors vous ne devez pas compter uniquement sur le Kernel / système d'exploitation ou la protection de mémoire -- mais également sur toutes les autres parties du système d'exploitation incluant les pilotes de dispositifs des tierces-parties.
Il existe d'autres techniques permettant au système d'exploitation de détecter que quelque chose «ne va pas» avec la mémoire d'un programme.
Données localisées: imaginez que plusieurs applications utilisent toutes une partie identique du système d'exploitation. Ce code pourrait emmagasiner ses données dans une zone «globale» (partagée par l'ensemble du système). Le problème c'est que cette zone doit être suffisamment grande pour contenir TOUTES les données possibles, de TOUS les programmes possibles qui peuvent être exécutés en même temps. Non seulement cela, mais si un programme a accès à cette zone de mémoire, alors il est toujours possible qu'il empiète sur les données d'un autre programme. Voilà pourquoi c'est une bonne idée de placer toutes les données d'un programme dans la zone de mémoire lui appartenant (localisée).
Erreurs d'adresses: certaines adresses de processeurs (tel le 68000 et le PowerPC) sont jumelées en groupes (groupes de 2, 4 ou 8), si le programme essaie d'aller vers une adresse «impaire», ou essaie d'accéder à un bloc de données inégal, alors le système peut détecter «une erreur d'adressage» et arrêter le programme. Puisque tous les programmes agissant ainsi sont de mauvaise qualité, ils doivent être arrêtés avant qu'ils n'endommagent d'autres applications ou leurs données.
Pages de garde: la plupart du temps, lorsqu'un programmeur commet une erreur, il s'agit d'une erreur appartenant à un petit groupe bien connu. Ainsi on peut prédire À QUEL ENDROIT ces erreurs peuvent tomber et y placer une page de garde (un garde qui surveille les accès non autorisés à cette zone et qui fait quitter l'application lorsqu'elle accède à cette zone). Cela protège contre la majorité des erreurs courantes faites par programmeur, telles que :
Ainsi même sans la pleine protection de mémoire, le système d'exploitation peut stopper la majorité des erreurs reliées à la mémoire en utilisant ces techniques partielles de protection.
Il y a beaucoup plus de chose contribuant à la stabilité d'un système que la seule protection de mémoire.
Vérification des paramètres: Imaginez que je mélange une commande que j'envoie au système (c'est habituellement un mélange de paramètres d'une sous-routine du système d'exploitation) -- le système peut ne pas savoir que je lui dis de faire de mauvaises choses. Puisque le système d'exploitation a lui-même accès à la mémoire des autres applications (et toute la quincaillerie), il est possible de faire un beau gâchis sans que la protection de mémoire n'y puisse quelque chose. Une technique peut protéger contre cela -- elle s'appelle vérification des paramètres -- c'est là que tous les paramètres sont vérifiés avant que la sous-routine soit exécutée.
Qualité du code du système d'exploitation: le système d'exploitation est composé de millions de lignes de code -- des erreurs s'y cachent. Heureusement la majorité des erreurs cachées dans le système requièrent un enchaînement complexe d'événements pour faire surface (autrement elles auraient déjà été localisées). Mais moins il y a d'erreurs et mieux c'est. La compagnie qui met le mieux en valeur la qualité du code (et qui fait beaucoup de tests) est celle qui a le plus de chance de produire un système d'exploitation stable. Les programmes ne sont aussi stables que le système d'exploitation lui-même.
Beaucoup d'autres questions sont à considérer, telles que la paramétrisation, la facilité d'utilisation, la qualité de la documentation, la qualité des outils et plus encore, tous contribuant à la stabilité du système d'exploitation et des applications.
Les nouveaux outils / Langages: l'assembleur, le C et le C++ sont mauvais pour la programmation en général. Ce sont des langages primitifs et «non sécuritaires». Java est un langage sécuritaire. Il est impossible (sans un bogue dans l'environnement Java) qu'une application touche à l'espace mémoire d'une autre application (il existe d'autres outils modernes qui sont également «sécuritaires»). La disponibilité de meilleurs outils rend la protection de mémoire au niveau du système d'exploitation beaucoup moins importante.
Si vous avez lu cet article au complet et que vous l'avez compris, alors vous possédez une compréhension de la protection de mémoire qui est supérieure à celle de plusieurs programmeurs. Vous réaliserez que la protection de mémoire n'est pas simple. C'est un ensemble de techniques différentes qui AIDENT à rendre un système d'exploitation plus stable. Aucune de ces techniques n'est le remède miracle contre les erreurs qu'un programmeur (ou une application de mauvaise qualité ou insuffisamment testée) peut faire.
Alors qu'est-ce que la protection de mémoire ? Qui a la protection de mémoire (1) ? Théoriquement c'est le système qui utilise une ou plusieurs de ces techniques -- ou -- c'est un système qui utilise TOUTES ces techniques! Le MacOS utilise plusieurs (la majorité) de ces techniques (et plusieurs s'ajoutent avec le temps) -- cependant certains disent que le Mac n'a pas de protection de mémoire. Certains disent que Windows95 a la protection de mémoire, il utilise peu de ces techniques (et pas en tout temps) -- et sans doute moins que ce que le Mac utilise. WinNT utilise un peu plus de ces techniques, Unix/Mach (Rhapsody et MacOS 9) en utilise encore plus. Mais il faut se demander également, pour chaque système d'exploitation, si ces techniques sont utilisées CORRECTEMENT. C'est une question relative et non pas absolue.
(1) De manière générale on dit que si vous avez la première technique de protection de mémoire (la protection globale du système) alors vous avez de la protection de mémoire. Un système qui n'utilise que la protection globale et n'utilise rien d'autre, a peu de chance d'être stable. C'est une question qui touche la qualité des applications et jusqu'à quel pointe votre système A BESOIN de la protection de mémoire.
N'oubliez jamais que la protection de mémoire contribue à la stabilité du système d'exploitation, mais que ce n'est pas le seul facteur -- tout comme la ceinture de sécurité protège en cas d'accident de voiture. Plusieurs autres choses contribuent à protéger une personne ou à prévenir un accident.