Libérer de la mémoire sur des objets volumineux [.NET] - C#/.NET managed - Programmation
Marsh Posté le 23-04-2007 à 21:12:59
ReplyMarsh Posté le 24-04-2007 à 10:56:40
Je me suis renseigné sur le GC.Collect, ça semble en effet être la bonne façon de faire pour libérer la mémoire, mais malheureusement ça ne change rien dans mon cas : dans mon exécution il passe dans le GC.Collect mais quand je regarde dans le gestionnaire des tâches, la mémoire ne cesse d'augmenter. Pourtant les objets volumineux appellent tous la fonction Dispose donc il devrait pouvoir me les vider
Marsh Posté le 24-04-2007 à 13:06:38
Je parle pas très bien VB et j'ai pas trop de temps pour analyser ton code, mais pour les objets à libérer :
* de manière générale vaut mieux faire un Dispose() et les mettre à null juste après.
Sinon ceux qu'il faut flinguer prioritairement :
* les images (comme tu l'as fait)
* tous les outils de GDI+ (Pen, Brush, Font)
* la connection à ta base de donnée
* les sql commandes
* les transactions
En l'occurence, très rapidement, essaye d'abord de mettre à null les objets que tu Dispose(), et dis-nous si ça résoud un peut tes pb.
Marsh Posté le 25-04-2007 à 13:30:38
moi23372 a écrit : fait un collect afin de forcer le garbage collector de passer sur les objets |
Très mauvaise idée. Le Collect effectue un parcours de la zone mémoire alloué à la CLR et la defrag en meme temps qu'elle libère des blocks de mémoire. C'est énormément chronophage (et niveau conso cpu, c'est pareil). D'une manière générale, il faut toujours laisser le système s'occuper de ce genre de chose, on est pas en C.
S'il a un memory leak, c'est qu'il y a un problème dans son code. Soigner le symptome n'est pas la solution. Il faut soigner la maladie.
Marsh Posté le 25-04-2007 à 13:32:31
rapidement je peux deja dire que remplacer ses horribles concaténation de string par un stringbuilder lui améliorera la mémoire.
Edit : ce qui consomme le plus ce sont les "string" car c'est immutable et ce n'est jamais libéré par le garbage collector.
Marsh Posté le 25-04-2007 à 14:18:04
Tamahome a écrit : rapidement je peux deja dire que remplacer ses horribles concaténation de string par un stringbuilder lui améliorera la mémoire. |
Pas en .Net 2.0
Ca a été amélioré
Et sinon je suis à 100% d'accord avec toi sur le GC.Collect().
Marsh Posté le 25-04-2007 à 15:46:44
Après plusieurs tests, j'i vu que GC.Collect() fonctionnait mais qu'il ne libérait que peu d'espace, il reste des objets très volumineux. J'ai changé le String en StringBuilder, ça a un peu diminué la mémoire mais pas encore assez. Ca atteint rapidement les 1 Go de mémoire utilisé donc ça ne peut pas être que sur des chaînes de caractères, il y a surement les images manipulées qui interviennent là dedans.
En fait je me demande si ça ne viendrait pas de ma table d'origine. Ma source c'est une DataTable assez grosse (8000 lignes) et qui contient aussi des images et je boucle avec un For oI = 0 To oDataTable.Count - 1 dedans. Seulement ce qui est étonnant c'est que je la charge intégralement dès le début de la migration et que ensuite je ne sais que l'exploiter, donc sa taille ne devrait pas augmenter.
Marsh Posté le 25-04-2007 à 17:17:27
tu peux essayer
- d'implémenter IDisposable dans tes objets et du coup de faire des using pour les objets créés dans cette méthode, et probablement dans la méthode qui appelle celle-ci sûrement en boucle,
- passer tes arguments par référence
edit : un très bon lien sur le GC (et les using, IDisposable, WeakReference..)
http://www.dotnetguru.org/articles/GC/GC.html
Marsh Posté le 26-04-2007 à 07:28:12
naglafar a écrit : Après plusieurs tests, j'i vu que GC.Collect() fonctionnait mais qu'il ne libérait que peu d'espace, il reste des objets très volumineux. J'ai changé le String en StringBuilder, ça a un peu diminué la mémoire mais pas encore assez. Ca atteint rapidement les 1 Go de mémoire utilisé donc ça ne peut pas être que sur des chaînes de caractères, il y a surement les images manipulées qui interviennent là dedans. |
Essaye en ne chargeant que la ligne dont tu as besoin. Utilise des using{} a la place des dispose, c'est plus pratique (ca appelle automatiquement le dispose. Sinon faut mettre les dispose() dans un finaly dans tes blocs try/catch pour etre sur que ce soit appellé...).
T'as posté l'intégralité du code au fait ? Si je le prends, ca compile ? (j'ai pas essayé)
Edit : ah merde c'est du vb.net
Marsh Posté le 26-04-2007 à 16:16:00
Merci beaucoup pour votre aide. J'ai trouvé d'où vient le problème mais vous ne pouviez pas le voir...
en fait c'est ma fonction qui génère la miniature de l'image qui ne libère pas bien la mémoire
oImage = xCasaque.xImage.GetImageByByte(oProduitImage.Document, New Size(250, 250))
oProduitImage.Miniature = xCasaque.xImage.GetByteByImage(oImage, oProduitImage.Extension)
J'ai pas encore cherché à quel endroit il y a un objet qui n'a pas été libéré mais maintenant que je sais d'où ça vient ça devrait être plus facile.
Marsh Posté le 23-04-2007 à 16:51:01
Bonjour,
Je suis en train de faire une reprise de données sur un catalogue et je dois notament passer d'un champ texte "image" à 2 champ dans la nouvelle base de données (SqlServer) de type image : un pour l'image, l'autre pour la miniature. Pour celà je dois donc ouvrir l'image a partir de son lien et ensuite l'enregistrer dans ma base de données.
Je fais déjà monImage.dispose(), maMiniature.dispose() et mon objet monProduit.dispose() qui contient toutes les propriétés et qui fait l'insert dans la base de données, mais malgrès ça, lorsque j'exécute et que je regarde les processus, la mémoire ne cesse d'augmenter jusqu'à saturation et message d'erreur "Mémoire insufisante".
Est-ce que quelqu'un a une idée pour m'aider à résoudre ce problème ?
Merci d'avance
Message édité par naglafar le 23-04-2007 à 17:57:42