Thread.Start : exception OutOfMemory
Le Contexte :
=============
En C# .Net1.1, sous visual studio 2003
nous avons développé un client-serveur en utilisant les fonctionnalités de System.Runtime.Remoting.
a réception de chaque message "nouveau chargement", nous lancons un thread permettant de traiter ce chargement.
ayant des problèmes de mémoire utilisée par notre serveur (application console),
nous avons ajouté à intervalle régulier l'appel à
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1) ;
et ajouté dans nos structures des fonctions Dispose finissant par :
GC.SuppressFinalize(this);
Ca semblait fonctionner, en regardant avec le gestionnaire de processus, le % de mémoire utilisé est stable entre 7 et 10Mo...
Le Problème
===========
En voulant rajouter une fonctionnalité à notre serveur, nous avons détecté le problème suivant :
sur une action Thread.Start nous avons l'exception "OutOfMemory". et notre serveur se bloque :=(
Ayant fait un programme de simulation qui envoie des messages au serveur et qui note toutes les 5mn l'état du processus server voila ce que j'obtiens :
07/06/2007 10:14:38 NbThreads=15 VMem=138 428 416
UserProcTime=00:00:00.3593750 TotalProcTime=00:00:00.9375000 PrivateMem=17203200
07/06/2007 10:19:38 NbThreads=22 VMem=442 904 576 UserProcTime=00:00:02.7343750 TotalProcTime=00:00:06.7812500 PrivateMem=30269440
07/06/2007 10:24:38 NbThreads=21 VMem=715 534 336 UserProcTime=00:00:04.3906250 TotalProcTime=00:00:11.7812500 PrivateMem=37363712
07/06/2007 10:29:38 NbThreads=22 VMem=1 002 844 160 UserProcTime=00:00:06.2031250 TotalProcTime=00:00:17.3593750 PrivateMem=44703744
et ca continue de croitre jusqu'à ce que VMem atteigne 2 000 000 000 et que nous ayons outofmemory.
(Vmem = Process.VirtualMemorySize, UserProcTime = Process.UserProcessorTime, TotalProcTime = Process.TotalProcessorTime
et PrivateMem =Process.PrivateMemorySize
Comme notre serveur est une application console qui lance des thread et que Microsoft (support.microsoft.com : article 828988) conseille de mettre en multithreading
c'est ce que j'ai fait...
[MTAThread]
static void Main
Mais pas mieux...
La Question
==============
Quelqu'un pourrait il m'expliquer ce qu'est cette memoire virtuelle ? et si ca pourrait etre liée à mon problème d'exception ?
Complement apres avoir utiliser des profiler
Après utilisation de MemoryProfiler et CLRProfiler :
de la mémoire virtuelle semble (entre autre) allouée dans l'appel de Open à ma base de données :
en gros je fais :
using System.Data.Odbc;
OdbcConnection oConn = new OdbcConnection(...);
OdbcCommand oCmd = MaFonctionCreationCmd(..);
oConn.Open();
... oCmd.Execute(); ...
oConn.Close();
oConn.dispose();
oConn = null;
j'ai Firebird 1.5.3.4870, OdbcDriver 1.2.0.69
Je n'arrive pas à définir si mes problèmes viennent des dll C# ou de celles de firebird.
MemProfiler me dit que c'est UnsafeNativeMethods.Odbc32.SQLDriverConnectW qui passe en code non managé...
Avant de faire ce code je ne "disposais" pas des connexions et des odbcommand, j'ai ajouté ce traitement mais ca ne modifie pas mon problème.
Gestion de la mémoire en .NET...
Bonjour,
le soucis que vous rencontrez peut-être réglé de façon "assez simple" par l'emploi des debugging tools windows. Ces outils sont par contre assez complexes à mettre en oeuvre... Si vous voulez des précisions, je pourrais vous en donner...
La mémoire en .Net est normalement gérée en interne via le GC (Garbage Collector). Mais le GC travaille en recherchant les objets vers lesquels il n'y a plus aucune référence, les marque pour "collection" (récupération de l'espace mémoire qu'ils utilisaient). Une fois les objets marqués pour "collection", à la prochaine exécution du GC, ils seront supprimés et transformé en espaces libres...
Le concept est un peu compliqué, mais dans les grandes lignes, si vous avez un tableau d'objets (type ArrayList / Hashtable ou Array simple) qui conserve les références... Vous ne libérerez jamais ces objets. Une bonne pratique consiste à mettre à null les références (mobjToto = null; ) pour que le GC n'est plus à chercher si la référence existe ou non... Si elle est à null, il marquera les objets directement pour "collection".
Un GROS point noir de la gestion mémoire en .Net concerne l'interopérabilité avec COM (si vous utilisez des composants COM, il y a des règles à mettre en oeuvre)...
Best Regards
Guillaume MARQUES