IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Thread.Start : exception OutOfMemory


Sujet :

C#

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 8
    Points : 6
    Points
    6
    Par défaut 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 ?

  2. #2
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 8
    Points : 6
    Points
    6
    Par défaut 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.

  3. #3
    Membre expert

    Homme Profil pro
    Consultant spécialité Firebird
    Inscrit en
    Mai 2002
    Messages
    2 342
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Consultant spécialité Firebird
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 342
    Points : 3 715
    Points
    3 715
    Par défaut
    Dispose() ne libère pas la mémoire
    c'est Collect() qui vide la poubelle
    si on ne fait que des Dispose() alors on a des memory leak
    Philippe Makowski
    IBPhoenix - Firebird
    Membre de l'April

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 8
    Points : 6
    Points
    6
    Par défaut Collect ne fait pas tout
    Bonjour,

    Merci pour votre réponse.
    Je faisais déjà GC.Collect(2);

    j'ai modifié par GC.collect();

    mais ca ne change rien :
    Mon test écrit dans la bd toutes les s et fait un collect toutes les 10 écritures, la taille de la mémoire virtuelle continue à croitre...

    TestSimulation lancé à 18/06/2007 08:45:32
    18/06/2007 08:45:56 TestDb : VMem=148 856 832 PrivateMem=13 418 496
    18/06/2007 08:45:56 TestDb : GC.Collect
    18/06/2007 08:45:56 TestDb : VMem=148 922 368 PrivateMem=13 561 856
    ...
    18/06/2007 08:50:08 TestDb : VMem=541 278 208 PrivateMem=21 880 832
    18/06/2007 08:50:08 TestDb : GC.Collect
    18/06/2007 08:50:08 TestDb : VMem=541 278 208 PrivateMem=21 880 832

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Points : 1 046
    Points
    1 046
    Par défaut
    Salut,

    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1) ;
    et ajouté dans nos structures des fonctions Dispose finissant par :
    GC.SuppressFinalize(this);
    Je ne connais pas SetProcessWorkingSetSize mais je pense pas que ce soit une bonne idée. Ensuite seule les classes qui ont qque chose a disposer (une ressource non managée en générale, comme un handle de fichier, une connexion base de données etc...) doivent implémenter IDisposeable et encore plus pour implémenter un finalizer (GC.SuppressFinalize(this) indique au CLR de ne plus appeler le finalizer de l'objet en cours puisque dispose a été appelé manuellement).

    Dispose() ne libère pas la mémoire
    c'est Collect() qui vide la poubelle
    si on ne fait que des Dispose() alors on a des memory leak
    Non. Comme dit plus haut dispose sert à libérer des ressources importantes manuellement sans attendre le passage du finalizer (car en général une classe qui possede une méthode dispose implémente aussi un finalizer). Appeler GC.Collect est déconseillé, mieux vaut laisser le garbage collector faire son boulot. Si tu te retrouves avec des OutOfMemoryException, de tte façon les GC.Collect ne feront rien pour t'aider, puisqu'a priori le systeme a déja tenté de libérer de la mémoire et qu'il n'y est pas arrivé d'ou l'exception.

    Quelqu'un pourrait il m'expliquer ce qu'est cette memoire virtuelle ? et si ca pourrait etre liée à mon problème d'exception ?
    Chaque process a une certaine taille de mémoire virtuelle associée. Sur un windows 32bits cette taille c'est 2Go. Cette mémoire n'est pas vraiment allouée au process, c'est a dire qu'elle ne correspond pas à de la mémoire physique tant que le process n'en a pas besoin. Apparemment ton process a demandé plus de 2Go de mémoire (c'est d'ailleurs ce que tu log). Deux possibilités au final: soit tu ne libères pas de la mémoire non managée explicitement (en appelant le dispose des objets qui utilisent de la mémoire non managée) , soit tu instancies beaucoup d'objets .net dont tu gardes une référence qque part ce qui empeche le GC de libérer la mémoire.

    EDIT: autre possibilité qd même: tu fais tout comme il faut mais tu utilises des objets développés par une autre boite qui ne libèrent pas de la mémoire, c'est possible aussi

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 51
    Points : 62
    Points
    62
    Par défaut 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

Discussions similaires

  1. Ruby, thread et exceptions
    Par boutintrain dans le forum Ruby
    Réponses: 1
    Dernier message: 20/04/2010, 20h41
  2. JSF exception outofmemory
    Par haskouse dans le forum JSF
    Réponses: 19
    Dernier message: 11/09/2009, 14h49
  3. Blocage de Thread.Start()
    Par minos2023 dans le forum C++/CLI
    Réponses: 0
    Dernier message: 28/04/2009, 16h40
  4. Réponses: 2
    Dernier message: 28/10/2008, 16h00
  5. thread et exceptions
    Par c_jm2 dans le forum Général Python
    Réponses: 7
    Dernier message: 02/04/2008, 14h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo