| Département de mathématiques et de statistique |
Gestion de la mémoire en S-Plus
Un des défauts de Splus, est sa manière de gérer sa mémoire. L'utilisation des boucles "for" est un exemple fréquemment rencontré.
Voici une boucle "for" traditionnelle:
for (i in 1:5000)
{
v <- var...
w <- sqrt...
x <- apply....
y <- apply....
z <- mean....
# affichage du
"i-ème" numéro de la boucle et du temps à tous les
250
# tours... (tout
ce qui est mis en "#" est un commentaire dans Splus).
if (i%%250==0) {cat(i, ") ", date(), "\n")}
}
Le problème avec ce type de fonction "for" est au niveau de l'allocation de la mémoire. Cette allocation est effectuée à chaque itération, en fonction du travail effectué lors d'une itération. Ainsi, le processus associé grossit en espace mémoire plus le nombre d'itérations augmente. Comme Splus ne se débarasse pas très bien de la mémoire qui n'est plus utilisée, on se retrouve avec de l'espace mémoire rendue inutile par Splus, que personne ne peut utiliser.
Pour faire un exemple, supposons qu'une itération de la fonction "for" précédente a besoin de "1024 bytes = 20 K" par tour de boucle. On se retrouve donc à la fin du "for", avec 5000 x 20K de mémoire => 100 Mb utilise par Splus. Le problème avec cette méthode est que la mémoire n'est rendue disponible qu'à la fin de toutes les itérations. Donc, pour des boucles "for" avec un grand nombre d'itérations, la mémoire utilise peut facilement grossir, ce qui ralenti Splus ainsi que les autres usagers sur la station ou le serveur utilisé. Effectivement, lorsqu'il n'y a plus de mémoire "vive" disponible, la machine utilise sa mémoire virtuelle (swapping) qui est beaucoup plus lente d'accès, ralentissant toutes les applications. Une borne sur la mémoire maximum sans trop ralentir les autres processus serait autour de la moitié de la mémoire vive disponible sur la station ou le serveur. Pour régler ce problème, on peut utiliser la boucle "For" (F majuscule). Ceci a pour avantage de ne considérer qu'un certain nombre d'itérations la fois au lieu d'un bloc total d'itérations, réduisant la perte de mémoire. Par exemple, au niveau de notre exemple précédent, voici l'équivalent avec une boucle "For" :
For(i=1:5000,
{
v <- var...
w <- sqrt...
x <- apply....
y <- apply....
z <- mean....
if (i%%250==0)
{cat(i, ") ", date(), "\n")}
}, grain.size=10)
Le grain.size défini le nombre d'itérations à effectuer , dans des processus indépendants de la fonction "For". Ceci veut dire que les 5000 itérations seraient divisées en 500 processus de 10 itérations, avec chaque processus utilisant sa propre mémoire allouée. De cette manière on obtient possiblement une économie sur la mémoire, augmentant la rapidité d'exécution du programme Splus. Il est a noter qu'il est possible que l'"object.size" soit trop petit lorsqu'on utilise ce type de boucle. C'est qu'avec un "For", la mémoire est allouée dès le départ du processus Splus associé, et non pas au fur et à mesure. Donc, il est possible que la taille maximale d'un objet (object.size) a besoin d'être ajustée (histoire de ne pas tomber en panne d'espace mémoire au cours de l'exécution).