Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour,
Nous travaillons sur un projet qui lance un traitement assez lourd (jusqu'à plusieurs heures en fonction du poste de travail).
Au cours de ce traitement, la taille de l'executable passe d'environ 44 Mo à plus de 500 Mo, et rien (ou quasiment) n'est relâché après.
Conclusion : l'application plante la mémoire du poste est saturée...
La taille de la base de données augmente aussi, encore plus rapidement que la taille de l'executable.
Voici les constatations que nous avons faites :
- Nous avons commencé par vérifier que tous les datastores étaient détruit après traitement => Pas de changement.
- Nous avons vérifié qu'il n'y avait pas de transaction ouverte et jamais détruite => pas de changement (il n'y en avait pas).
- Avec un déco/reco de la transaction SQLCA, la taille de la base de donnée reprend une taille "normale". En revanche la taille de l'executable de bouge pas.
- Nous n'utilisons pas d'object OLE.
- Nous utilisons des objets auto-instancié qui semble se détruirent correctement à la fermeture, mais qui ne semblent pas libérer de mémoire (!)
- Nous utilisons beaucoup de datastores et du SQL embarqué, avec plusieurs curseurs toujours détruits après utilisation.
- Nous utilisons beaucoup de variables d'instances (environ 200) avec des datastores, des tableaux dynamiques (ou pas), des structures et pas mal de string et de long...
- Un datastore est rempli tout au long du traitement pour atteindre plusieurs milliers de lignes afin de générer le fichier final.
Question : Qu'est-ce qui peut faire gonfler à ce point la taille de l'exécutable et de la base de données ?!
Hors ligne
salut
pour la base : les transactions ...
pour que la base puisse faire des rollback
En sql server tu peux ajouter des WITH (NOLOCK ) si tu n'as pas besoin de verrouiller la tables ...
Hors ligne
Bonjour,
Certaines versions de Powerbuilder sont connues pour présenter des fuites de mémoire. Il est préférable pour cela d'utiliser le dernier EBF.
Malgré tout, j'ai observé ce phénomène de fuite de mémoire dans notre application lors de procédure d'import avec une quantité importante de données.
Après analyse, j'ai remarqué que la mémoire n'était pas libéré correctement à la sortie de certaines méthodes.
J'ai modifié les arguments des méthodes pour passer les variables par référence pour éviter de dupliquer inutilement en mémoire de grandes quantités de données,
j'ai pu faire disparaître totalement le phénomène.
D'autre part, il peut être intéressant d'utiliser la fonction GarbageCollect() pour forcer la libération de la mémoire.
Hors ligne
bonjour,
merci pour votre aide...
Je n'ai pas précisé l'environnement : PB 11.2 avec une base Firebird 2.1
J'ai tenté de mettre des GarbageCollect() un peu partout sans succès (en mode débugage, la mémoire semble même augmenter au passage du garbageCollect() !)
Je viens d'installer le dernier EBF, sans aucun changement.
Les autres pistes sont interessantes, mais trop longues à mettre en place, sachant qu'il ne me reste que quelques heures pour trouver l'origine du problème et le corriger.
Hors ligne
Une astuce pour vérifier c'est de commenter dichotomiquement des portions de codes pour retrouver les coupables de fuites...
Hors ligne
Bonjour
Si possible sur le sql serveur, éviter d'utiliser des curseurs, cela diminue les performances du SGBD.
Il vaut mieux utiliser des tables temporaires et reformuler ses requêtes.
Hors ligne
Aloneg a écrit:
PB 11.2 avec une base Firebird 2.1
Tu te connecte comment à Firebird ? ODBC ? Avec quel driver ?
Hors ligne
Via ODBC, avec les drivers Firebird ODBC - légèrement modifiés il y a plusieurs années pour corriger un problème lié à Firebird -
Sinon nous avons trouvé une explication, mais qui m'étonne un peu... nous créons dynamiquement des datastores pendant le traitement.
Avant modif : plusieurs datastores étaientt créés dans chaque boucle et détruit à la fin, vu les volumes on pouvait créé plusieurs milliers de datastore.
Après modif : les datastores sont créés et chargés une seule fois, et on utilise des filtres à l'intérieur des boucles. Ce qui ne fait créé plus que quelques dizaines de datastores.
Ce qui voudrait dire que la mémoire n'est rendue qu'en partie par PB à la destruction d'un datastore, et que c'est le cumul de miliers de créations/destructions qui serait à l'origine du problème.
Hors ligne
Si tu crées dynamiquement un objet dans une boucle comme ceci :
MonType l_objet Long l_i, l_max l_max = 100 FOR l_i = 1 TO l_max l_objet = CREATE MonType .......suite du code.... NEXT
un nouvel objet est crée à chaque occurrence de la boucle et le pointeur l_objet vient pointer sur cette nouvelle occurrence. Mais on perd du même coup la référence sur l'objet pointé au tour de boucle précédent, rendant impossible la libération de la mémoire.
A+
Hors ligne
Ce qui était fait avant, qui fait exploser la mémoire :
MonType l_objet Long l_i, l_max l_max = 100 FOR l_i = 1 TO l_max l_objet = CREATE MonType .......suite du code.... DESTROY l_objet NEXT
Ce que l'on fait maintenant, qui est nettement moins consommateur de mémoire
MonType l_objet Long l_i, l_max l_max = 100 l_objet = CREATE MonType FOR l_i = 1 TO l_max ... traitement avec des filtres... NEXT DESTROY l_objet
ma question est : pourquoi ??
Hors ligne
Aloneg a écrit:
ma question est : pourquoi ??
Si ce sont des datastores, je pense que c'est lié à l'évolution de la gestion de l'allocation mémoire
par PB depuis la version 7: Il ne détruit pas certains objets pour pouvoir les
ré-allouer plus rapidement en cas de demande, même si un "DESTROY" explicite a été codé.
La raison de cette modification serait liée à l'évolution du produit vers la gestion d'applications N-tiers et
web. J'avais eu le souci chez un client, qui, du coup, est resté à la version PB6.5.
Hors ligne
Est-ce que tu utilises des datastores ou des objets descendants ?
Dans le deuxième cas, si ils ont en variables d'instance des autoinstanciates, il est possible que la mémoire ne soit pas libéré tout de suite après le Destroy... Un appel à garbagecollect ou yield peut aider la PBVM à libérer ces objets mais coûtera du temps cpu.
Hors ligne
Merci Foon... c'est effectivement l'explication la plus probable puisque ce sont des datastores que nous crééons "à la volée".
Mais s'il n'y a vraiment aucun moyen de détruire complètement un datastore, ça voudrait dire que les applications construites en PB sont condamnées à consommer toujours plus de mémoire sans la relâcher avant la fermeture complète ?? C'est quand même ballot non ?
@xlat : C'est bien un objet auto-instancié qui créé les datastores, mais visiblement un GarbageCollect() ne libère rien de plus... je n'ai pas testé le Yield(), à voir.
Hors ligne