OVH Cloud OVH Cloud

Détruire un objet avant la fin du script ?

50 réponses
Avatar
ctobini
Bonjour =E0 tous et meilleurs voeux pour 2006 (la sant=E9 surtout) !

J'ai cr=E9=E9 un script objet en m'aidant de didacticiels en r=E9f=E9rence
sur le forum et j'ai un petit probl=E8me concernant la destruction
d'objet.

J'ai cr=E9=E9 une classe dont le constructeur est du sytle $self =3D
{'array1' =3D [], 'array2' =3D [], 'hash1' =3D {} ...}

Dans les didacticiels il est donc indiqu=E9 qu'on peut utiliser une
classe DESTROY qui n'est utilis=E9e qu'en fin de programme.

Je voudrais d=E9truire un objet une fois celui-ci utilis=E9 afin de
lib=E9rer de la m=E9moire et continuer mon script (j'ai pour l'instant
700 Mo de RAM utilis=E9s pour 750 dispo, je stocke de gros fichiers
texte).

J'ai tent=E9 de r=E9initialis=E9 mes valeurs en r=E9affectant $self =3D
{'array1' =3D [], 'array2' =3D [], 'hash1' =3D {} ...} et en v=E9rifiant
l'=E9tat en cr=E9ant un boucle while (1 =3D=3D 1) {} mais j'ai toujours 700
Mo occup=E9s.

Merci beaucoup si vous pouvez m'aider, c'est assez urgent et pour le
boulot :-)

C=2E Tobini

10 réponses

1 2 3 4 5
Avatar
Nicolas George
"ctobini" wrote in message
:
Je voudrais détruire un objet une fois celui-ci utilisé afin de
libérer de la mémoire et continuer mon script (j'ai pour l'instant
700 Mo de RAM utilisés pour 750 dispo, je stocke de gros fichiers
texte).


Une valeur en mémoire cesse d'exister quand elle n'est plus accessible aux
fonctions en exécution (sauf s'il y a un cycle dans les références). Il
suffit de supprimer sa référence pour la faire disparaître. La méthode
DESTROY est appelée à ce moment-là si c'est un objet. Voici un exemple :

use strict;
use warnings;

{
package Exemple;

sub new {
my ($class) = @_;
return bless {}, $class;
}
sub DESTROY {
print "DESTROY!n";
}
}

{
my $t = Exemple->new;
print "Objet cree.n";
sleep 3;
print "Fin du crochet.n";
sleep 1;
}
sleep 1;
print "Apres le crochet.n";

Avatar
Paul Gaborit
À (at) 2 Jan 2006 06:25:07 -0800,
"ctobini" écrivait (wrote):
Bonjour à tous et meilleurs voeux pour 2006 (la santé surtout) !


... et tout, itou ;-)

J'ai créé un script objet en m'aidant de didacticiels en référence
sur le forum et j'ai un petit problème concernant la destruction
d'objet.

J'ai créé une classe dont le constructeur est du sytle $self > {'array1' = [], 'array2' = [], 'hash1' = {} ...}


Ok.

Dans les didacticiels il est donc indiqué qu'on peut utiliser une
classe DESTROY qui n'est utilisée qu'en fin de programme.


DESTROY est une *méthode* implicite. Elle est appelée automagiquement
pour un objet juste avant que Perl ne le détruise. Un objet est
détruit dès qu'il n'est plus référencé. Dans un cas simple, cela
arrive lorsqu'on affecte une autre valeur au scalaire qui référence
l'objet, lorsque qu'on termine le bloc contenant la déclaration de ce
scalaire ou lorsque le script se termine si le scalaire est déclaré
globalement.

Je voudrais détruire un objet une fois celui-ci utilisé afin de
libérer de la mémoire et continuer mon script (j'ai pour l'instant
700 Mo de RAM utilisés pour 750 dispo, je stocke de gros fichiers
texte).


C'est fait tout seul (cf. ci-dessus). Pour voir à quel moment cela se
passe, on peut afficher une trace dans la méthode DESTROY de la
classe :

sub DESTROY {
warn __PACKAGE__ . "::DESTROYn";
# avec en plus un affichage pour reconnaitre l'objet
# concerné qui est référencé dans $_[0]...
}

J'ai tenté de réinitialisé mes valeurs en réaffectant $self > {'array1' = [], 'array2' = [], 'hash1' = {} ...} et en vérifiant
l'état en créant un boucle while (1 == 1) {} mais j'ai toujours 700
Mo occupés.


C'est normal. Perl ne rend *jamais* la mémoire au système (si ce n'est
en fin de script). Il la garde sous le coude pour la réutiliser.

Merci beaucoup si vous pouvez m'aider, c'est assez urgent et pour le
boulot :-)


Heu... Ça, ça ne comnpte pas !

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
ctobini
Bonjour à tous et merci de vos réponses, désolé de répondre
tardivement.

D'après ce que vous me dites, si j'appelle un ou plusieurs package(s)
situé(s) dans un .pm depuis un script .pl, les objets seront détruits
et la mémoire libérée à la fin du script ?

Dans ce cas, à part utiliser 2 scripts pour un traitement, il n'y a
pas moyen de libéré la mémoire, même si l'utilisateur sais qu'à
telle étape du script les objets précédemment créés ne servent
plus ?

C. Tobini
Avatar
Paul Gaborit
À (at) 5 Jan 2006 04:45:35 -0800,
"ctobini" écrivait (wrote):
D'après ce que vous me dites, si j'appelle un ou plusieurs package(s)
situé(s) dans un .pm depuis un script .pl, les objets seront détruits
et la mémoire libérée à la fin du script ?


Le fait que vous utilisiez des modules ou que tous vos packages soit
décrits dans un seul fichier importe peu. Le fait d'utiliser des
objets ou de simples structures (éventuellement complexes) importe
peu.

Dans ce cas, à part utiliser 2 scripts pour un traitement, il n'y a
pas moyen de libéré la mémoire, même si l'utilisateur sais qu'à
telle étape du script les objets précédemment créés ne servent
plus ?


Il y a deux notions différentes dans vos termes "libérer la mémoire".

1- La notion du point de vue du programmeur Perl :

Si je crée des données en mémoire, cette mémoire restera occupée tant
que ces données seront encore référencées par le script. Par contre,
dès que ces données ne seront plus référencées (par exemple lorsqu'un
objet est détruit en fin de bloc), perl saura réutiliser la mémoire
correspondante pour d'autres données (sauf dans le cas des références
cycliques qu'il faut casser "à la main"). La mémoire peut donc bien
être "libérer" et "réutiliser" au fur et à mesure des besoins.

2- La notion du point de vue du système :

Un script Perl demande de la mémoire au système au fur et à mesure de
ses besoins. Mais perl ne rend jamais cette mémoire au système... sauf
lorsque le script se termine. La mémoire utilisée n'est donc jamais
"libérée".

En résumé, la mémoire libérée par perl n'est réutilisable que par perl
tant que le script n'est pas terminé. perl n'est pas le seul dans ce
cas : la plupart de softs fonctionnent comme cela.

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
FDA

Un script Perl demande de la mémoire au système au fur et à mesure de
ses besoins. Mais perl ne rend jamais cette mémoire au système... sauf
lorsque le script se termine. La mémoire utilisée n'est donc jamais
"libérée".

En résumé, la mémoire libérée par perl n'est réutilisable que par perl
tant que le script n'est pas terminé. perl n'est pas le seul dans ce
cas : la plupart de softs fonctionnent comme cela.


35 ans après qu'un langage comme PL/I ait permis des allocations et
libérations hiérarchisées avec ses notions d'offset de d'area, c'est
tout de même malheureux que la technique ait rétrogradé à ce point... :-(

Avatar
Paul Gaborit
À (at) Thu, 05 Jan 2006 17:00:37 +0100,
FDA écrivait (wrote):

Un script Perl demande de la mémoire au système au fur et à mesure de
ses besoins. Mais perl ne rend jamais cette mémoire au système... sauf
lorsque le script se termine. La mémoire utilisée n'est donc jamais
"libérée".
En résumé, la mémoire libérée par perl n'est réutilisable que par
perl
tant que le script n'est pas terminé. perl n'est pas le seul dans ce
cas : la plupart de softs fonctionnent comme cela.


35 ans après qu'un langage comme PL/I ait permis des allocations et
libérations hiérarchisées avec ses notions d'offset de d'area, c'est
tout de même malheureux que la technique ait rétrogradé à ce
point... :-(


Il n'y a rien de rétrograde...

Quelques éléments de réflexion :

Ce n'est pas Perl (le langage) qui est en cause mais perl (l'une de
ses implémentations actuelles).

PL/I seul ne peut rien faire de mieux car pour que ça marche, il faut
évidemment la participation du système (qui doit pouvoir récupérer la
mémoire libéré). Certains systèmes ne permett(ai)ent tout simplement
pas de rendre la mémoire.

Avec l'avénement de la mémoire virtuelle dans la quasi totalité de OS
*et* des processeurs, ce problème n'en est souvent plus un (sauf dans
le cas de softs serveurs destinés à tourner très longtemps). On peut
même montrer qu'il donne souvent de meilleures performances que
d'autres stratégies d'allocation. C'est surtout vrai avec des langages
"morcelés" comme Lisp, Java, Perl, Python ou C++ qui n'arrêtent pas de
créer et détruire un grand nombre d'objets alors que les langages
procéduraux d'antan travaille soit en allocation quasi-statique
(Fortran avant 90) soit via la pile (comme le C si on fait abstraction
des appels système free/alloc/(s)brk).

Par ailleurs, la plupart des softs (comme certains SGBD par exemple)
qui savent réellement libérer leur mémoire (en la rendant au système)
le font via une bibliothèque intermédiaire de gestion mémoire pour ne
pas utiliser les mécanismes d'allocation simpliste et généraux des
langages ou du système. Cela leur permet de choisir une stratégie de
gestion mémoire adaptée à leur besoin.

La fable habituelle :

- Le concepteur du langage C disait "la gestion de l'allocation
mémoire est une chose tellement importante qu'on ne peut la laisser au
système".

- Le concepteur du langage Lisp disait "la gestion de l'allocation
mémoire est une chose tellement importante qu'on ne peut pas la
laisser au programmeur".

La vérité est entre les deux :

- En C++ (qui avait une stratégie genre C), on voit maintenant des
bibliothèques de gestion d'allocation pour améliorer les performances.

- En Java (qui avait une stratégie genre Lisp), on voit maintenant
qu'on peut paramètrer voire remplacer le ramasse-miettes standard pour
améliorer les performances.

En Perl, pour l'instant, on en est à la manière Lisp (ou Java de base)
avec un ramasse-miettes très rapide (mais qui ne gère pas les
cycles). Il y a des discussions pour Perl6 (et Parot) qui offrira
certainement la possibilité d'implémenter sa propre stratégie mais je
ne sais pas où ça en est...

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>


Avatar
FDA

Ce n'est pas Perl (le langage) qui est en cause mais perl (l'une de
ses implémentations actuelles).


C'est clair.


PL/I seul ne peut rien faire de mieux car pour que ça marche, il faut
évidemment la participation du système (qui doit pouvoir récupérer la
mémoire libéré). Certains systèmes ne permett(ai)ent tout simplement
pas de rendre la mémoire.


C'est cela qui me semble aberrant. L'un des services de base d'un
système consiste précisément à allouer et à reprendre (sur demande) de
la mémoire aux applications. Autant la limitation que tu indiques est
justifiée sur les très vieux systèmes de temps partagé où chaque
processus se voit préallouer une tranche de mémoire, autant il me semble
dépourvu de sens aujourd'hui.

Pour prendre une comparaison simple, en Linux, même si tu possède un
quota de taille disque, le système ne te le préalloue pas, ne t'oblige
pas à l'avoir de façon contibue sur /home, et ne t'interdit pas de
restituer l'espace. Cela, c'était bon il y a 35 ans sur l'IBM 1130 !


Avec l'avénement de la mémoire virtuelle dans la quasi totalité de OS
*et* des processeurs, ce problème n'en est souvent plus un (sauf dans
le cas de softs serveurs destinés à tourner très longtemps).


J'avoue ne pas comprendre. Tu utilises encore la mémoire virtuelle, toi?
Cela fait deux ans que j'ai inhibée la mienne aussi bien sous Windows
que sous Linux : pagespace à 0, swap space à 0 (l'installation t'avertit
d'un message, mais te donne le droit de passer outre) : à quoi me
servirait-il d'avoir une machine avec un p-rating équivalant à 3,8
millions d'opérations par seconde si, même une fois tous les dix
millions d'opérations, je dois attendre 8ms un appel disque ? Je préfère
carrément que le système se bloque sur un "Memory full" et aller acheter
une barrette mémoire de plus au revendeur du coin.

De toute façon, si les échanges disque commencent, tout rame tellement
que tu es obligé d'arrêter le traitement toi-même... Ce ne sont tout
simplement pas les mêmes ordres de gradeur qui sont en présence. Et
aujourd'hui moins que jamais.


La fable habituelle :

- Le concepteur du langage C disait "la gestion de l'allocation
mémoire est une chose tellement importante qu'on ne peut la laisser au
système".

- Le concepteur du langage Lisp disait "la gestion de l'allocation
mémoire est une chose tellement importante qu'on ne peut pas la
laisser au programmeur".


:-) Il y a du vrai.

Avatar
Paul Gaborit
À (at) Thu, 05 Jan 2006 17:51:43 +0100,
FDA écrivait (wrote):
J'avoue ne pas comprendre. Tu utilises encore la mémoire virtuelle,
toi? Cela fait deux ans que j'ai inhibée la mienne aussi bien sous
Windows que sous Linux : pagespace à 0, swap space à 0 (l'installation
t'avertit d'un message, mais te donne le droit de passer outre) : à
quoi me servirait-il d'avoir une machine avec un p-rating équivalant à
3,8 millions d'opérations par seconde si, même une fois tous les dix
millions d'opérations, je dois attendre 8ms un appel disque ? Je
préfère carrément que le système se bloque sur un "Memory full" et
aller acheter une barrette mémoire de plus au revendeur du coin.

De toute façon, si les échanges disque commencent, tout rame tellement
que tu es obligé d'arrêter le traitement toi-même... Ce ne sont tout
simplement pas les mêmes ordres de gradeur qui sont en présence. Et
aujourd'hui moins que jamais.


Heu... C'était peut-être vrai des système d'antan. Mais de nos jours,
lorsqu'un processus a besoin d'une page mémoire placé sur disque,
évidemment il doit attendre (bien moins de 8ms si les données sont
encore dans le cache du disque) mais les autres processus continuent
de fonctionner sans aucun problème. Et puis, un processus a bien
d'autres occasions d'être bloqué : l'accès à la carte son, à la carte
graphique, au réseau, au données d'un disque distant, l'attente d'une
frappe clavier, etc. et parfois bien plus longtemps que le temps
d'accès au swap. Dans ce cas, je ne vois pas le problème si une partie
de sa mémoire se retrouve sur le swap si cela permet par exemple à
d'autres processus de bénéficier de plus de cache pour leur accès aus
données.

Là encore tout n'est pas noir ou blanc... La gestion de la mémoire
n'est qu'un vaste compromis.

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
Paul Gaborit
À (at) Thu, 05 Jan 2006 17:51:43 +0100,
FDA écrivait (wrote):
[...] Je préfère carrément que le système se bloque sur un "Memory
full" et aller acheter une barrette mémoire de plus au revendeur du
coin.


Juste pour cette question : je préfère que le système ralentisse
momentanément plutôt que de ne pas pouvoir exécuter la tâche
ultra-importante que je dois justement terminer tout de suite pour
quelques ko manquant occupés par des tâches moins
prioritaires... alors que ce besoin de surplus assuré par un peu de
swap ne durera que quelques secondes ou minutes. Évidemment si cela
doit durer plus longtemps, c'est qu'il est temps d'acheter soit de la
mémoire soit un autre ordinateur ;-)

Ceci étant... On s'éloigne de plus en plus de Perl ;-)

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
FDA


Juste pour cette question : je préfère que le système ralentisse
momentanément plutôt que de ne pas pouvoir exécuter la tâche
ultra-importante que je dois justement terminer tout de suite pour
quelques ko manquant occupés par des tâches moins
prioritaires... alors que ce besoin de surplus assuré par un peu de
swap ne durera que quelques secondes ou minutes. Évidemment si cela
doit durer plus longtemps, c'est qu'il est temps d'acheter soit de la
mémoire soit un autre ordinateur ;-)

Ceci étant... On s'éloigne de plus en plus de Perl ;-)


Je voulais juste dire que sur une application unique et avec les tailles
de RAM que nous avons, si tu as *un* défaut de page, alors tu en auras
rapidement quelques dizaines ou centaines de milliers, donc ce n'est pas
même la peine de commencer.

Je ne sais pas si perl fait confiance à l'OS pour gérer son espace
mémoire. Windows procède de façon ahurissante, puisqu'il fait du
*chaînage en mémoire virtuelle* , le meilleur moyen, d'avoir des
performances qui s'effondrent; je ne sais pas d'ailleurs si
l'architecture 386 lui laisse vraiment le choix.

À vouloir cacher au programmeur la différence entre ce qui est en
mémoire et ce qui n'y est pas, on finit par lui faire écrire sans qu'il
y puisse rien des choses magnifiquement contre-performantes :-(

Pour terminer sur ce point, en supprimant le dispositif de swapping, on
y gagne au moins de ne pas devoir le charger en mémoire si le système
est écrit correctement. C'est toujours (éventuellement) cela de gagné.

1 2 3 4 5