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.