Aller au contenu

%ALLOC

Réserver de la mémoire

Réserve un bloc de mémoire de la taille demandée, en octets, et renvoie un pointeur sur son début.

Syntaxe

%ALLOC(taille)
taille
Le nombre d'octets à réserver, sous forme d'une expression numérique entière.
Résultat
Un pointeur sur le début de la mémoire réservée.

À quoi ça sert

Un tableau déclaré avec dim(1000) occupe toujours 1000 éléments, même si on n'en utilise que trois. Avec %ALLOC, on ne prend que la place nécessaire, en fonction de ce qu'on découvre à l'exécution (nombre de lignes lues, longueur d'un texte).

On déclare le tableau ou la structure avec based(pointeur), on affecte le résultat de %ALLOC au pointeur, puis on utilise la zone comme d'habitude. Tout bloc réservé doit être rendu avec dealloc.

Exemple 1 : Un tableau à la bonne taille

**free
// %ALLOC : reserver de la memoire au moment de l'execution, puis la rendre.
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-s p pointer;
dcl-s villes char(12) dim(50) based(p);
dcl-s nb int(10) inz(4);
dcl-s i int(10);

// On reserve exactement la place de 4 villes (4 x 12 octets).
p = %alloc(nb * %size(villes(1)));
snd-msg 'Memoire reservee : ' + %char(nb * %size(villes(1))) + ' octets';

villes(1) = 'Montpellier';
villes(2) = 'Lyon';
villes(3) = 'Brest';
villes(4) = 'Nantes';

for i = 1 to nb;
  snd-msg 'Ville ' + %char(i) + ' : [' + villes(i) + ']';
endfor;

// dealloc(n) rend la memoire ET remet le pointeur a *NULL.
dealloc(n) p;
snd-msg 'Pointeur nul apres liberation ? ' + %char(p = *null);

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Memoire reservee : 48 octets
Ville 1 : [Montpellier ]
Ville 2 : [Lyon        ]
Ville 3 : [Brest       ]
Ville 4 : [Nantes      ]
Pointeur nul apres liberation ? 1

Le tableau est déclaré pour 50 villes, mais on n'en réserve que 4 : 48 octets. dealloc(n) p rend la mémoire et remet le pointeur à *NULL, ce que confirme la dernière ligne.

Exemple 2 : Une demande trop grosse

**free
// %ALLOC : que se passe-t-il quand la demande est trop grosse ?
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-ds sds psds qualified;
  msgid char(7) pos(40);
  msgtxt char(80) pos(91);
end-ds;
dcl-s p pointer;
dcl-s taille int(10);

monitor;
  taille = 1000000;
  p = %alloc(taille);
  snd-msg '1 Mo : reservation reussie';
  dealloc(n) p;
  taille = 20000000;
  p = %alloc(taille);
  snd-msg '20 Mo : reservation reussie';
  dealloc(n) p;
on-error;
  snd-msg 'Echec : ' + sds.msgid + ' ' + %trim(sds.msgtxt);
endmon;

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

1 Mo : reservation reussie
Echec : RNX0425 La longueur demandée pour l'allocation de mémoire est hors limites.

1 Mo passe, 20 Mo échoue avec RNX0425 (longueur demandée hors limites). Le programme rattrape l'erreur avec monitor.

Exemple 3 : Le même programme avec alloc(*teraspace)

**free
// %ALLOC : avec alloc(*teraspace), la meme demande de 20 Mo reussit.
ctl-opt dftactgrp(*no) actgrp(*new) alloc(*teraspace);

dcl-ds sds psds qualified;
  msgid char(7) pos(40);
  msgtxt char(80) pos(91);
end-ds;
dcl-s p pointer;
dcl-s taille int(10);

monitor;
  taille = 1000000;
  p = %alloc(taille);
  snd-msg '1 Mo : reservation reussie';
  dealloc(n) p;
  taille = 20000000;
  p = %alloc(taille);
  snd-msg '20 Mo : reservation reussie';
  dealloc(n) p;
on-error;
  snd-msg 'Echec : ' + sds.msgid + ' ' + %trim(sds.msgtxt);
endmon;

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

1 Mo : reservation reussie
20 Mo : reservation reussie

Avec le mot-clé alloc(*teraspace) dans ctl-opt, la même réservation de 20 Mo réussit.

Le piège

Par défaut, les gros blocs sont refusés. Une demande de 20 Mo échoue avec l'erreur RNX0425 à l'exécution (exemple 2), alors que 1 Mo passe. Le mot-clé alloc(*teraspace) de ctl-opt permet la même demande (exemple 3).

N'oubliez jamais dealloc : un bloc non rendu reste réservé. Le tableau based de l'exemple 1 déclare 50 éléments alors que 4 seulement sont réservés : c'est à vous de ne pas dépasser.