OVH Cloud OVH Cloud

Occupation Memoire - .Net 1.1

11 réponses
Avatar
Michael Moreno
Bonjour,

Nous developpons plusieurs applications de type serveur avec un GUI
tres peu riche et elles prennent vraiment beaucoup plus de RAM que si
nous avions developpe ces memes applis dans un langage Win32.

Chaque appli prend environ 50 MB de RAM + 50MB de memoire virtuelle.
Nous avons 5 applis => 250 MB de RAM + 250 MB de RAM virtuelle !!!

Si nous laissons tourner ces applications sans faire appel au
GC.Collect() certaines de ces applis prennent plus de 200MB de RAM et
autant de memoire virtuelle et on atteint rapidement plus de 600 MB de
RAM et autant de memoires virtuelles.

Ces applications doivent tourner en meme temps sur un serveur central
sur lequel SQL Serveur est aussi installe.

Nous avons note que le fait de laisser le GC gerer la memoire affecte
les performances de SQL serveur car il a tout simplement moins de RAM
et de memoire virtuelle.

Nous avons donc conclu qu'il fallait faire appel au GC.Collect au moins
une fois toutes les minutes dans nos applis clientes (meme probleme sur
machine cliente) et serveurs.

Avez-vous ce meme genre de probleme ?

Merci,
Michael

--
Michael
----
http://michael.moreno.free.fr/
http://port.cogolin.free.fr/

10 réponses

1 2
Avatar
Cyber Sinh
Michael Moreno a écrit :
Bonjour,

Nous developpons plusieurs applications de type serveur avec un GUI tres
peu riche et elles prennent vraiment beaucoup plus de RAM que si nous
avions developpe ces memes applis dans un langage Win32.

Chaque appli prend environ 50 MB de RAM + 50MB de memoire virtuelle.
Nous avons 5 applis => 250 MB de RAM + 250 MB de RAM virtuelle !!!

Si nous laissons tourner ces applications sans faire appel au
GC.Collect() certaines de ces applis prennent plus de 200MB de RAM et
autant de memoire virtuelle et on atteint rapidement plus de 600 MB de
RAM et autant de memoires virtuelles.

Ces applications doivent tourner en meme temps sur un serveur central
sur lequel SQL Serveur est aussi installe.

Nous avons note que le fait de laisser le GC gerer la memoire affecte
les performances de SQL serveur car il a tout simplement moins de RAM et
de memoire virtuelle.

Nous avons donc conclu qu'il fallait faire appel au GC.Collect au moins
une fois toutes les minutes dans nos applis clientes (meme probleme sur
machine cliente) et serveurs.

Avez-vous ce meme genre de probleme ?

Merci,
Michael



Bonjour,
Il n'est pas recommandé d'utiliser directement la méthode
GC.Collect()... la CLR s'occupant de nettoyer la mémoire automatiquement
au moment le plus opportun pour ne pas ralentir l'exécution de
l'application.
Si le GC ne nettoie pas la mémoire, c'est qu'il estime que le RAM ne
vient pas à manquer sur le système. Combien de RAM disposez-vous sur
votre serveur ?

Cyber Sinh
Avatar
Michael Moreno
Bonjour,

Il n'est pas recommandé d'utiliser directement la méthode GC.Collect()... la
CLR s'occupant de nettoyer la mémoire automatiquement au moment le plus
opportun pour ne pas ralentir l'exécution de l'application.



Certes mais ca ne le fait pas, le disque swappe a tout va et ca
ralentit SQL Server (BDD > 200 GB).
Il s'agit d'une appli financiere temps reel et les CPU sont a 50% du
temps a pleine charge ou pas loin (i.e > 90%).

Si le GC ne nettoie pas la mémoire, c'est qu'il estime que le RAM ne vient
pas à manquer sur le système. Combien de RAM disposez-vous sur votre serveur
?



Serveurs de test 1 et 2 GB. Chez nos clients on a en pratique 1 ou 2
GB. On a un seul cas extreme avec 512 GB.
En moyenne l'appel a GC.Collect() prend 3,7 ms toutes les minutes ce
qui est tres peu donc le CLR devrait le faire tout seul sauf si bien
sur il ne le fait que quand l'appli est Idle ou que la charge du CPU
est < 20% ce qui n'arrive jamais.

Merci.

--
Michael
----
http://michael.moreno.free.fr/
http://port.cogolin.free.fr/
Avatar
Tsunoo Rhilty
Peut-etre cet article t'aidera (anglais)
http://www.issociate.de/board/index.php?t=msg&gotoQ6656&rid=0
Avatar
Michael Moreno
> Peut-etre cet article t'aidera (anglais)
http://www.issociate.de/board/index.php?t=msg&gotoQ6656&rid=0



Merci bien, j'essaie en meme temps de comprendre ce qui se passe avec
AQTime mais c'est vraiment difficile.
Je vais verifier tout le code pour voir si il y a des fuites de
memoire.

--
Michael
----
http://michael.moreno.free.fr/
http://port.cogolin.free.fr/
Avatar
Simon Mourier [SoftFluent]
Sauf à utiliser l'interop manuellement, (est ce votre cas?), on ne peut pas
en .NET faire de "fuite mémoire" physique. Par contre, on peut tout à fait
faire des fuites logiques, par exemple une hashtable statique dans laquelle
on ajoute en permanence des éléments, sans jamais les vider.

A priori, si, quand vous lancez le GC manuellement, la mémoire retombe à un
niveau stable, c'est que vous n'avez ni fuite physique, ni fuite logique.
Cela signifie simplement que votre programme consomme trop de mémoire à
l'instant T.

En ASP.NET vous pouvez régler des paramètres de recyclage automatique du
processus, mais c'est un peu violent (et il faut voir si votre application
supporte un recyclage, ce qui n'est pas toujours le cas). Par contre, c'est
pratique.

Si vous n'êtes pas en ASP.NET ou que votre application ne supporte pas le
recyclage, il faut que vous analysiez plus finement votre code, par exemple
avec des outils de profiling tels que CLR profiler:

CLR Profiler 1.1
http://www.microsoft.com/downloads/details.aspx?FamilyId†CE6052-D7F4-4AEB-9B7A-94635BEEBDDA&displaylang=en

CLR Profiler 2.0
http://www.microsoft.com/downloads/details.aspx?FamilyId£62781C-3870-43BE-8926-862B40AA0CD0&displaylang=en

How to use CLR profiler
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenethowto13.asp

Using GC efficiently
http://blogs.msdn.com/maoni/

Simon.
www.softfluent.com


"Michael Moreno" a écrit dans le message
de news:
Peut-etre cet article t'aidera (anglais)
http://www.issociate.de/board/index.php?t=msg&gotoQ6656&rid=0



Merci bien, j'essaie en meme temps de comprendre ce qui se passe avec
AQTime mais c'est vraiment difficile.
Je vais verifier tout le code pour voir si il y a des fuites de memoire.

--
Michael
----
http://michael.moreno.free.fr/
http://port.cogolin.free.fr/



Avatar
Patrice Manac'h
Bonjour,

le GC collecte par défaut tout ce qui est libéré mais quelques astuces
permettent de lui simplifier la vie. La plus courant est pour tous les
objects IDisposable de faire explicitement lorsqu'ils ne sont plus utilisés
:
- un Close si c'est disponible.
- un Dispose.
- et de mettre la variable à null.

C'est simple mais cela peut très vite payer. Pour le comprendre, il faut
regarder comment le GC fonctionne. Par défaut, il gère 3 zones mémoires dont
la taille par processeur est de l'ordre de :
- quelques dizaines de Ko pour les objets les plus récents.
- quelques Mo pour les objets en génération 1.
- plus de 10 Mo pour les objets en génération 2.

Lorsque le système manque de mémoire (besoin d'allocation, génération 0, 1
ou 2 pleine, etc), le GC créé pour chaque génération un graphe de dépendance
de manière à déterminer quels objets peuvent être virer. Si un objet est
IDisposable mais pas disposé, le GC le Dispose et le monte en génération
supérieure. Lors d'un prochain GC, il sera viré. Mais si le Dispose avait
été fait à la main, il aurait été viré tout de suite.

Le résultat est que les générations 1 et 2 se remplissent et que vu la
taille de ces blocs, la construction du graphe devient de plus en plus
couteuse.

Essayer de travailler ce point de prime abord. Des dumps mémoire (windgb,
.Net Profiler) pourraient aussi permettre de savoir si les ressources sont
bien libérées.

Cordialement,

Patrice

"Michael Moreno" a écrit dans le message
de news:
Bonjour,

Il n'est pas recommandé d'utiliser directement la méthode GC.Collect()...
la CLR s'occupant de nettoyer la mémoire automatiquement au moment le
plus opportun pour ne pas ralentir l'exécution de l'application.



Certes mais ca ne le fait pas, le disque swappe a tout va et ca ralentit
SQL Server (BDD > 200 GB).
Il s'agit d'une appli financiere temps reel et les CPU sont a 50% du temps
a pleine charge ou pas loin (i.e > 90%).

Si le GC ne nettoie pas la mémoire, c'est qu'il estime que le RAM ne
vient pas à manquer sur le système. Combien de RAM disposez-vous sur
votre serveur ?



Serveurs de test 1 et 2 GB. Chez nos clients on a en pratique 1 ou 2 GB.
On a un seul cas extreme avec 512 GB.
En moyenne l'appel a GC.Collect() prend 3,7 ms toutes les minutes ce qui
est tres peu donc le CLR devrait le faire tout seul sauf si bien sur il ne
le fait que quand l'appli est Idle ou que la charge du CPU est < 20% ce
qui n'arrive jamais.

Merci.

--
Michael
----
http://michael.moreno.free.fr/
http://port.cogolin.free.fr/



Avatar
Michael Moreno
Merci bien pour toutes ces informations.

--

----------------------------------------------

http://michael.moreno.free.fr/
Avatar
Michael Moreno
Merci bien pour ces explications.

--

----------------------------------------------

http://michael.moreno.free.fr/
Avatar
Bruno Jouhier
"Patrice Manac'h" a écrit dans le message de
news:
Bonjour,

le GC collecte par défaut tout ce qui est libéré mais quelques astuces
permettent de lui simplifier la vie. La plus courant est pour tous les
objects IDisposable de faire explicitement lorsqu'ils ne sont plus
utilisés :
- un Close si c'est disponible.
- un Dispose.
- et de mettre la variable à null.



La seule chose à appeler c'est Dispose. Mettre la variable à null ne sert en
général à rien.
En C#, il est conseillé d'utiliser la construction "using" (voir la doc).


C'est simple mais cela peut très vite payer. Pour le comprendre, il faut
regarder comment le GC fonctionne. Par défaut, il gère 3 zones mémoires
dont la taille par processeur est de l'ordre de :
- quelques dizaines de Ko pour les objets les plus récents.
- quelques Mo pour les objets en génération 1.
- plus de 10 Mo pour les objets en génération 2.

Lorsque le système manque de mémoire (besoin d'allocation, génération 0, 1
ou 2 pleine, etc), le GC créé pour chaque génération un graphe de
dépendance de manière à déterminer quels objets peuvent être virer. Si un
objet est IDisposable mais pas disposé, le GC le Dispose et le monte en
génération supérieure. Lors d'un prochain GC, il sera viré. Mais si le
Dispose avait été fait à la main, il aurait été viré tout de suite.



Le GC ne construit pas de graphes de dépendances (comment les
maintiendrait-il à jour en permanence?) et il ne regarde pas si les objets
implémentent IDisposable. En revanche, il s'intéresse aux finaliseurs
(destructeurs).

Le rôle de IDisposable, ce n'est pas de libérer la mémoire des objets .NET
plus tôt, c'est de libérer les ressources "non managées" référencées par des
objets .NET.
En lisant ce qui précède, on a l'impression qu'on peut améliorer les choses
en mettant des interfaces IDisposable et des appels à Dispose partout, ce
qui serait une grosse erreur.
IDisposable et Dispose n'ont de sens que si les objets .NET en question
référencent (directement ou indirectement) des ressources "non managées". Et
l'appel à Dispose ne fait que libérer la ressource non managée et empêcher
que l'objet .NET passe dans la queue de finalisation (si l'objet référence
"directement" une ressource non managée, il est de bon ton qu'il ait un
finaliseur, et Dispose doit inhiber le finaliseur dans ce cas). Dispose n'a
aucun impact sur la façon dont le GC gère les générations d'objets.


Le résultat est que les générations 1 et 2 se remplissent et que vu la
taille de ces blocs, la construction du graphe devient de plus en plus
couteuse.



Non, le GC ne fonctionne pas comme ça.


Essayer de travailler ce point de prime abord. Des dumps mémoire (windgb,
.Net Profiler) pourraient aussi permettre de savoir si les ressources sont
bien libérées.

Cordialement,

Patrice

"Michael Moreno" a écrit dans le message
de news:
Bonjour,

Il n'est pas recommandé d'utiliser directement la méthode
GC.Collect()... la CLR s'occupant de nettoyer la mémoire automatiquement
au moment le plus opportun pour ne pas ralentir l'exécution de
l'application.



Certes mais ca ne le fait pas, le disque swappe a tout va et ca ralentit
SQL Server (BDD > 200 GB).
Il s'agit d'une appli financiere temps reel et les CPU sont a 50% du
temps a pleine charge ou pas loin (i.e > 90%).

Si le GC ne nettoie pas la mémoire, c'est qu'il estime que le RAM ne
vient pas à manquer sur le système. Combien de RAM disposez-vous sur
votre serveur ?



Serveurs de test 1 et 2 GB. Chez nos clients on a en pratique 1 ou 2 GB.
On a un seul cas extreme avec 512 GB.
En moyenne l'appel a GC.Collect() prend 3,7 ms toutes les minutes ce qui
est tres peu donc le CLR devrait le faire tout seul sauf si bien sur il
ne le fait que quand l'appli est Idle ou que la charge du CPU est < 20%
ce qui n'arrive jamais.

Merci.

--
Michael
----
http://michael.moreno.free.fr/
http://port.cogolin.free.fr/







Avatar
Patrice Manac'h
Bonjour,

tout dépend de la portée de la vairable.Mettre à null peut servir. Quand au
Dispose, vous ne devez pas supposer que Dispose l'appelle implicitement.

Cordialement,

P. Manac'h
MCS France

"Bruno Jouhier" a écrit dans le message de news:
43d5d60e$0$26396$
"Patrice Manac'h" a écrit dans le message
de news:
Bonjour,

le GC collecte par défaut tout ce qui est libéré mais quelques astuces
permettent de lui simplifier la vie. La plus courant est pour tous les
objects IDisposable de faire explicitement lorsqu'ils ne sont plus
utilisés :
- un Close si c'est disponible.
- un Dispose.
- et de mettre la variable à null.



La seule chose à appeler c'est Dispose. Mettre la variable à null ne sert
en général à rien.
En C#, il est conseillé d'utiliser la construction "using" (voir la doc).


C'est simple mais cela peut très vite payer. Pour le comprendre, il faut
regarder comment le GC fonctionne. Par défaut, il gère 3 zones mémoires
dont la taille par processeur est de l'ordre de :
- quelques dizaines de Ko pour les objets les plus récents.
- quelques Mo pour les objets en génération 1.
- plus de 10 Mo pour les objets en génération 2.

Lorsque le système manque de mémoire (besoin d'allocation, génération 0,
1 ou 2 pleine, etc), le GC créé pour chaque génération un graphe de
dépendance de manière à déterminer quels objets peuvent être virer. Si un
objet est IDisposable mais pas disposé, le GC le Dispose et le monte en
génération supérieure. Lors d'un prochain GC, il sera viré. Mais si le
Dispose avait été fait à la main, il aurait été viré tout de suite.



Le GC ne construit pas de graphes de dépendances (comment les
maintiendrait-il à jour en permanence?) et il ne regarde pas si les objets
implémentent IDisposable. En revanche, il s'intéresse aux finaliseurs
(destructeurs).

Le rôle de IDisposable, ce n'est pas de libérer la mémoire des objets .NET
plus tôt, c'est de libérer les ressources "non managées" référencées par
des objets .NET.
En lisant ce qui précède, on a l'impression qu'on peut améliorer les
choses en mettant des interfaces IDisposable et des appels à Dispose
partout, ce qui serait une grosse erreur.
IDisposable et Dispose n'ont de sens que si les objets .NET en question
référencent (directement ou indirectement) des ressources "non managées".
Et l'appel à Dispose ne fait que libérer la ressource non managée et
empêcher que l'objet .NET passe dans la queue de finalisation (si l'objet
référence "directement" une ressource non managée, il est de bon ton qu'il
ait un finaliseur, et Dispose doit inhiber le finaliseur dans ce cas).
Dispose n'a aucun impact sur la façon dont le GC gère les générations
d'objets.


Le résultat est que les générations 1 et 2 se remplissent et que vu la
taille de ces blocs, la construction du graphe devient de plus en plus
couteuse.



Non, le GC ne fonctionne pas comme ça.


Essayer de travailler ce point de prime abord. Des dumps mémoire (windgb,
.Net Profiler) pourraient aussi permettre de savoir si les ressources
sont bien libérées.

Cordialement,

Patrice

"Michael Moreno" a écrit dans le
message de news:
Bonjour,

Il n'est pas recommandé d'utiliser directement la méthode
GC.Collect()... la CLR s'occupant de nettoyer la mémoire
automatiquement au moment le plus opportun pour ne pas ralentir
l'exécution de l'application.



Certes mais ca ne le fait pas, le disque swappe a tout va et ca ralentit
SQL Server (BDD > 200 GB).
Il s'agit d'une appli financiere temps reel et les CPU sont a 50% du
temps a pleine charge ou pas loin (i.e > 90%).

Si le GC ne nettoie pas la mémoire, c'est qu'il estime que le RAM ne
vient pas à manquer sur le système. Combien de RAM disposez-vous sur
votre serveur ?



Serveurs de test 1 et 2 GB. Chez nos clients on a en pratique 1 ou 2 GB.
On a un seul cas extreme avec 512 GB.
En moyenne l'appel a GC.Collect() prend 3,7 ms toutes les minutes ce qui
est tres peu donc le CLR devrait le faire tout seul sauf si bien sur il
ne le fait que quand l'appli est Idle ou que la charge du CPU est < 20%
ce qui n'arrive jamais.

Merci.

--
Michael
----
http://michael.moreno.free.fr/
http://port.cogolin.free.fr/











1 2