Document fait avec Nvu Document made with Nvu




Allocation dynamique de la mémoire

Instructions
Utilisation
Exemple

Principe

Si le langage FORTH est peu gourmand en occupation mémoire pour ce qui concerne le code, il en va autrement lorsqu'il s'agit de traiter des données de tailles importantes comme les fichiers graphiques par exemple (ceci est d'ailleurs valable quelque soit le langage de programmation).

Il est donc indispensable d'optimiser l'utilisation de la mémoire contenant les données sachant que, d'une part, la taille de la mémoire ne sera jamais infinie et que, d'autre part, toutes les applications ne sont jamais activées simultanément.

Le langage FORTH ne permet à la base que l'allocation statique de mémoire à l'aide principalement de l'instruction "ALLOT". Cette instruction réserve le nombre de mots de 16 bits passé comme argument sur la pile des données. Ces mots sont directemen pris dans l'espace du vocabulaire et ne peuvent pas être libérés pour une autre application.

A l'opposé, l'allocation dynamique de la mémoire donne le moyen à chaque application d'allouer de la mémoire en fonction de son besoin et la restituer une fois que le programme est terminé. Ainsi, une autre application pourra récupérer cet espace mémoire.

Le pilote que j'ai créé organise la mémoire sous la forme d'une liste chaînée de blocs dont la taille dépend des requêtes de chaque application :

HERE+50000 Limite de la mémoire disponible
... ...
Bloc 1 Adresse du bloc 2 + état occupé
0
Contenu du bloc 1
Bloc 2 Adresse du bloc 3 + état occupé ou libre
Adresse du bloc 1
Contenu du bloc 2
... ...
Bloc n Adresse du bloc n+1 + état occupé ou libre
Adresse du bloc n-1
Contenu du bloc n
... ...
Fin de la liste 0
Adresse du dernier bloc


Un bloc, élément de la liste chaînée, est composé de 3 partie :

  • les 4 premiers octets contiennen la taille en octets de la troisième partie du bloc (multiple de 8 octets). Les 3 bits de poids faibles indiquent que le bloc est libre si ils sont tous les 3 à zéro. Si le bit 0 est à 1, le bloc est réservé par une application. Les bits 1 et 2 sont réservés pour une évolution future et doivent actuellement toujours être à zéro.
  • les 4 octets suivant sont constitués du complément à 1 (inversion bit à bit) des 4 premiers octets. Il permettent ainsi au système de vérifier la cohérence de la liste chaînée.
  • les octets suivants corresponden aux données réservées par l'application. L'adresse du premier de ces octets doit être mémorisé par l'application les utilisant.

Les 8 derniers octets de la mémoire contiennent une taille nulle pour marquer la fin de la liste chaînée qui correspond à la fin de la mémoire.


Instructions

- MEMOIRE_ADRESSE adresse

Adresse du début de la mémoire allouable dynamiquement.
Cette variable est réservée au système

- MEMOIRE_PROBLEME -

Procédure d'arrêt du système après détection d'une anomalie dans la liste chaînée.
Cette instruction est réservée au système

- T_MEMOIRE_CONTROLE adresse

Tâche de contrôle de la liste chaînée.
Cette tâche est gérée par le système

taille MEMOIRE_ALLOUE adresse

Allocation d'un bloc mémoire ayan la taille précisée.
L'adresse est nulle si l'allocation est impossible

adresse MEMOIRE_LIBERE b

Libération d'un bloc mémoire.
b est nul si l'opération s'est effectuée correctement

- MLIST -

Liste les blocs de mémoire en indiquan leur état d'occupation, leur taille et leur adresse.


Utilisation

Une application n'a besoin d'utiliser que 2 des instructions précédemment définies : "MEMOIRE_ALLOUE" et "MEMOIRE_LIBERE".

La première permet à l'application de réserver un bloc mémoire dont la taille est envoyée comme paramètre d'entrée. Le paramètre de sortie est l'adresse du début du bloc alloué à moins que le manque de place n'occasionne une valeur nulle. Dans le premier cas, l'application devra mémoriser cette adresse et travailler avec celle-ci. Dans le second, l'application devra gérer l'erreur en le signalant le cas échéant.

La deuxième permet à l'application de restituer le bloc mémoire alloué lorsqu'elle n'en a plus besoin. Ce bloc sera alors disponible pour une autre application. Les blocs libres adjacents sont systématiquemen concaténés afin que les applications puissent disposer de tailles de bloc les plus grandes possibles.

La tâche de contrôle surveille régulièrement (toutes les 5 secondes environ) la cohérence de la liste chaînée des blocs. Si une application dépasse la taille mémoire qu'elle a réservée, elle peut alors détruire l'entête du bloc suivant, ce qui sera détecté par cette tâche. Cette dernière lancera alors la procédure d'arrê du système en le signalant à l'opérateur à l'aide de l'instruction "MEMOIRE_PROBLEME".

L'instruction "MLIST" donne au développeur un moyen de visualiser les paramètres des différents blocs de la mémoire.


Exemple

Supposons que votre application nécessite l'utilisation d'un tampon de 100 Kilo Octets (éditeur de texte par exemple). Au lieu de réserver ce tampon dans la zone du vocabulaire à l'aide de l'instruction "ALLOT" (allocation statique), vous allez allouer cet espace lorsque l'application sera activée en vous contentant de créer une variable destinée à mémoriser l'adresse du tampon:

0 VARIABLE TAMPON_100K

: APPLICATION
 100000 MEMOIRE_ALLOUE ?DUP

 IF

  TAMPON_100K 2!

  ... programme correspondant à l'application ...

  TAMPON_100K 2@ MEMOIRE_LIBERE DROP

 ELSE

  ... procédure signalan qu'il n'y a pas de mémoire disponible ...

 THEN

;

Cet exemple relativement simple démontre que seules 2 instructions sont nécessaires.

Prenons maintenant un cas plus concre prenant avantage du noyau temps réel. Celui-ci permet de mettre en attente l'application lorsqu'il n'y a pas de mémoire disponible et de la lancer dès que possible:

0 VARIABLE TAMPON_100K

TACHE: T_APPLICATION
 100000 MEMOIRE_ALLOUE ?DUP

 IF

  TAMPON_100K 2!

  ... programme correspondant à l'application ...

  TAMPON_100K 2@ MEMOIRE_LIBERE DROP

  T_APPLICATION T_RETIRE

 ELSE

  100 T_APPLICATION T_ACTIVE

 THEN

;

: APPLICATION
 ... initialisation de l'application ...

 32768 T_APPLICATION T_AJOUTE 10 T_APPLICATION T_ACTIVE

;

Ce deuxième exemple montre l'avantage d'utiliser un noyau temps réel combiné à l'allocation dynamique de la mémoire. Vous pouvez ainsi initialiser plusieurs applications partageant le même espace mémoire à des moments différents. Ces moments seront automatiquement gérés par le noyau temps réel.