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 :

[C#] Question garbage collector


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Par défaut [C#] Question garbage collector
    Bonjour à tous,
    j'ai un petit souci de mémoire dans un mes programmes.
    En je fait un readAllBytes sur un fichier et j'envoie par socket. Du coup la consommation mémoire du programme augmente, jusque la pas de souci cependant en quittant la méthode la mémoire n'est pas libérer comme cela se fait ??

    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
            private void    Download(String Destinataire, String Commande, Byte[] Ele)
            {
                try
                {
                    String name = System.Text.Encoding.Unicode.GetString(Ele);
                    name = name.Substring(0, name.Length - 1);
                    Byte[] tab = System.IO.File.ReadAllBytes(name);
                    Int32 size = tab.Length;
                    Int32 i = 0;
                    Byte[] tosend = null;
                    FileInfo f = new FileInfo(name);
                    Byte[] tmp = System.Text.Encoding.ASCII.GetBytes(f.Name);
                    Byte[] zero = System.Text.Encoding.ASCII.GetBytes("\0");
                    long s = f.Length;
                    Byte[] siz = System.Text.Encoding.ASCII.GetBytes(Convert.ToString(s) + "\0");
                    while (i < size)
                    {
                        if (i + 65536 <= size)
                            tosend = Packet.SubByte(tab, i, i + 65536);
                        else
                            tosend = Packet.SubByte(tab, i, size);
                        tosend = Packet.Copy(zero, tosend);
                        tosend = Packet.Copy(tmp, tosend);
                        tosend = Packet.Copy(siz, tosend);
                        Byte[] packet = Packet.BuildPacket(Destinataire, Commande, tosend);
                        this.PushSend(packet);
                        i += 65536;
                    }
                }
                catch (Exception)
                {
                }
            }

    Merci d'avance !

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Parce que le garbage collector ne passe pas immédiatement... ton tableau est sorti du scope, donc il est éligible pour le garbage collector, qui libèrera la mémoire associée lors de son prochain passage. On ne peut pas prévoir exactement quand le garbage collector, il le fera quand il jugera que ça devient nécessaire

    Par contre, à mon avis ce n'est pas une bonne idée de charger tout le fichier en mémoire... tu ferais mieux de le lire au fur et à mesure de l'envoi, avec un Stream. Ca éviterait d'avoir des pics de consommation de mémoire, vu que tu n'utiliserais que N octets à la fois (N étant la taille de ton buffer)

  3. #3
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Par défaut
    ba hier j'ai test avec une fichier d'un go ... en local, il la mis en mémoire et 30 min plus tard il lavait toujours pas libérer...'(et 1go en mémoire ca commence à faire ... bon j'ai certe 4go mais quand même). Donc je me pose des question s'il passe toute les heures c'est pas très utile ^^

    Le temps de passage dépend-il de la quantitée de mémoire libre restant sur l'ordinateur ?

    Et comment faire pour lire que 64ko a la fois, avec un binary reader ? il y a une méthode qui fait cela ?

    Merci

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par NeoKript Voir le message
    ba hier j'ai test avec une fichier d'un go ... en local, il la mis en mémoire et 30 min plus tard il lavait toujours pas libérer...'(et 1go en mémoire ca commence à faire ... bon j'ai certe 4go mais quand même). Donc je me pose des question s'il passe toute les heures c'est pas très utile ^^

    Le temps de passage dépend-il de la quantitée de mémoire libre restant sur l'ordinateur ?
    Je sais pas quelle est la "politique" exacte de passage du GC, mais en tous cas c'est pas une question de temps. Mais effectivement c'est surprenant que pour un Go il le libère pas plus rapidement... Tu es sûr qu'il ne reste aucune référence sur ce tableau ? Ta classe Packet ne garde pas une référence dessus ?

    Sinon tu peux toujours appeler le GC explicitement après avoir enlevé toutes els références (méthode GC.Collect), mais en général on évite de faire ça car c'est assez couteux en ressources...

    Citation Envoyé par NeoKript Voir le message
    Et comment faire pour lire que 64ko a la fois, avec un binary reader ? il y a une méthode qui fait cela ?
    En général on considère que la taille de buffer optimale est plutôt de 8Ko (8192 octets).
    Pas besoin de BinaryReader (qui sert plutôt à lire des données typées à partir d'un flux binaire), un Stream est suffisant.
    Il faut juste que tu alloues un buffer, dans lequel tu charges les données en boucle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    using (Stream stream = File.OpenRead(leFichier))
    {
        byte[] buffer = new byte[8192];
        int nBytesRead = stream.Read(buffer, 0, buffer.Length);
        while(nBytesRead > 0)
        {
            // envoyer les nBytesRead premiers octets du buffer (en général c'est le buffer entier, sauf quand tu arrives en fin de fichier)
     
            nBytesRead = stream.Read(buffer, 0, buffer.Length);
        }
    }

  5. #5
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    Vis à vis du passage du GC, beaucoup de choses compte, y compris la mémoire actuellement disponible sur le système.

    Sinon, ReadAllBytes c'est mal car tu n'as absolument aucun contrôle sur la quantité de mémoire qui sera allouée. Le mieux si cette fonction ne peut être accédée que par un seul thread à la fois c'est d'avoir un buffer statique de taille fixe (8 - 32 ko) dont tu va te servir et ce sera la seule et unique allocation dans tout ton programme alors que si tu le met dans une fonction, tu aura une allocation à chaque appel sans libération immédiate.

    Après, pour éviter d'avoir une variable statique ou gérer le cas d'une fonction pouvant être appelée par plusieurs threads à la fois, il peut être efficace d'envisager l'utilisation d'un pool de buffer (genre allouer dès le départ une dizaine de byte[] de 8 ko et les récupérer quand besoin est, les remettre quand ce n'est plus nécessaire).
    (je dois avoir ça sous le coude d'ailleurs, mais ce n'est pas difficile à faire en implémentant IDisposable).

    Le but à chaque fois c'est avoir une quantité déterminée de buffers car il vaut mieux avoir 512 ko de pool alloué dès le départ et ne pas souvent s'en servir que ReadAllBytes ou un buffer à chaque appel et avoir un programme qui consomme des quantités folles de mémoire lors d'une utilisation poussée.

  6. #6
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 197
    Par défaut
    il me semble que le gc est en grande partie appelé suite à une demande de l'OS

    on peut faire le parallère avec windows qui depuis quelques années à changé de méthode de gestion de la mémoire
    tout le monde s'est plain avec l'arrivée de vista qu'il "bouffe toute la ram"
    c'est juste que y a de la ram dispo donc il met des choses dedans des fois qu'il y en ait besoin, et si c'est le cas on gagne du temps, si c'est pas le cas et qu'il faut mettre autre chose c'est pas grave on vide et on met ce qu'il y a à mettre, c'est pour ca que quand on met 4Go sur vista et qu'on lance rien il va quand meme prendre au moins 3Go

    sql server fonctionne aussi comme ca, dès qu'il lit quelque chose il le met en ram, mais ne le rend jamais meme si on ne lui demande plus
    par contre quand l'OS a besoin de place il lui dit et sql server rend alors les choses les moins utilisées

    on met de plus en plus de ram sur nos pc, si c'est pour ne pas l'utiliser ca sert à rien autant ne pas en mettre

    pour en revenir au GC, certes il se presse pas trop dans la vie, mais quand l'OS lui dit qu'il a besoin de mémoire il fait son boulot
    donc si tu as 4Go de ram, tant que windows n'en pas besoin de 5 les 1Go alloués par ton appli risque d'y rester

    après pour des traitements avec des pics de mémoire et sans solution plus propre (comme ici ne pas lire tout en une seule fois) il reste possible d'appeler le GC manuellement
    il est conseillé de faire l'appel sur un autre thread car ca consomme du temps rien qu'à l'appel
    car lors de l'appel de l'OS on peut quand même imaginé que ca prend plus de temps de libérer la mémoire au moment de la remplir avec autre chose, alors que si ca avait été vidé sur du temps libre il n'y aurait pas eut de perte
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [JVM] Java 5 et Garbage Collector(Parralèle)
    Par ssaunois dans le forum Général Java
    Réponses: 6
    Dernier message: 28/11/2005, 23h42
  2. [JVM]Garbage collector
    Par godik dans le forum Général Java
    Réponses: 5
    Dernier message: 07/10/2005, 09h12
  3. JPanel et Garbage Collector
    Par tck-lt dans le forum Agents de placement/Fenêtres
    Réponses: 9
    Dernier message: 25/07/2005, 18h03
  4. [JVM] les objets et le Garbage collector
    Par Kurdran dans le forum Général Java
    Réponses: 7
    Dernier message: 02/06/2005, 16h57
  5. [Language]Garbage collector
    Par GETah dans le forum Langage
    Réponses: 2
    Dernier message: 23/03/2005, 15h18

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