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 :

Besoin d'aide sur consommation mémoire


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2006
    Messages
    256
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 256
    Par défaut Besoin d'aide sur consommation mémoire
    Bonjour,

    J'ai un souci avec mon programme, j'ai une consommation mémoire croissante que je ne comprends pas du tout. J'ai analysé mon code mais je ne trouve aucune piste.

    A son lancement mon programme lance un thread qui me remplit un listview en mode virtuel :

    Procédure que le thread appelle :
    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
     
            private void UpdateListeFax()
            {
                faxes = zf.GetFaxes(config.FAX_emetteur_nom);
                if (listeCache == null) listeCache = new List<ListViewItem>();
                this.Invoke(new MethodInvoker(delegate
                {
                    listfax.Items.Clear();
                    listfax.VirtualMode = true;
                    listfax.HeaderStyle = ColumnHeaderStyle.Clickable;
                    listfax.VirtualListSize = faxes.Count;
                }));
                retourftp = true;
                UpdaterState = new UpdateState(maj_state_liste);
                _AddFax = new AddFax(AddListeFax);
                StartThreads(); // lance les threads de traitement
            }
    Quand le remplissage de la liste est terminé, on appelle la procédure StartThreads qui me lance deux nouveaux threads, un qui vérifie la connexion à un serveur de fax toutes les 30s :

    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
     
            private void server_check()
            {
                while (!Tcancel)
                {
                    if (!zf.CheckServer(out zf_err))
                    {
                        StopConnection();
                        reconnectzetafax();
                    }
                    else
                    {
                        // On met à jour les stats
                        zf.UpdateStats(faxes);
                        this.Invoke(new MethodInvoker(delegate
                        {
                            lock (this)
                            {
                                // On affiche les stats
                                lbstat.Text = String.Format("Fax en attente : {0} - Fax envoyés : {1} - Fax échoués : {2} - Total des fax : {3}",
                                    zf._GlobalState.fax_waiting, zf._GlobalState.fax_ok, zf._GlobalState.fax_failed, zf._GlobalState.fax_all);
                            }
                        }));
                    }
                    Threading.Thread.Sleep(TimerDelay2);
                }
                Logger("Fin du thread 2");
            }
    Un autre qui regarde toutes les 500 ms s'il faut envoyer des fax au serveur et qui vérifie le statut des fax existants :

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
     
            private void check()
            {
                fax newfax;
                bool sended, verif_file;
                string fic;
     
                while (!Tcancel)
                {
                    // On traite les fichiers .cfg
                    foreach (string folder in lstdossiers)
                    {
                        if (IO.Directory.Exists(folder))
                        {
                            foreach (string FI in IO.Directory.GetFiles(folder, "*.cfg", IO.SearchOption.TopDirectoryOnly))
                            {
                                Logger("Fichier " + FI + " trouvé");
                                Logger("Vérification de l'accès au fichier");
                                if (CheckFile(FI))
                                {
                                    sended = false;
                                    // On récupère les informations utiles
                                    Logger("Récupération des valeurs du fichier pour le traitement du fax");
                                    if (ini.RecupererValeur("Envoi", "Protocole", FI).ToUpper() == "FAX" |
                                        ini.RecupererValeur("Envoi", "Protocole", FI).ToUpper() == "HPRIMMEDECIN")
                                    {
                                        newfax = new fax();
                                        newfax.Id = Guid.NewGuid();
                                        newfax.dateajout = new IO.FileInfo(FI).CreationTime;
                                        newfax.to = new string[,] {
                                {ini.RecupererValeur("Envoi", "Medecin", FI),
                                ini.RecupererValeur("Envoi", "Telephone", FI)}};
     
                                        fic = ini.RecupererValeur("Envoi", "Fichier", FI);
                                        verif_file = false;
     
                                        Logger("Nom fichier joint : " + fic);
                                        for (int n = 0; n < config.FAX_emetteur_hostnamesfile.Count; n++)
                                        {
                                            Logger("Vérification de l'accés au fichier " + config.FAX_emetteur_hostnamesfile[n] + fic);
                                            verif_file = CheckFile(config.FAX_emetteur_hostnamesfile[n] + fic);
                                            if (verif_file)
                                            {
                                                fic = config.FAX_emetteur_hostnamesfile[n] + fic;
                                                break;
                                            }
                                            Threading.Thread.Sleep(10);
                                        }
                                        if (verif_file)
                                        {
                                            newfax.files = new string[] { fic };
                                            newfax.From = config.FAX_emetteur_nom;
                                            newfax.Dossier = ini.RecupererValeur("Envoi", "NumDossier", FI);
                                            newfax.CodeMedecin = ini.RecupererValeur("Envoi", "CodeMedecin", FI);
                                            newfax.FaxPatient = ini.RecupererValeur("Envoi", "FaxPatient", FI);
                                            newfax.RetourAs400 = false;
                                            Logger("Envoi du fax au serveur");
                                            if (zf.SendMessage(ref newfax, out zf_err))
                                            {
                                                do
                                                {
                                                    zf.GetInfosFax(true, ref newfax, out zf_err);
                                                    Threading.Thread.Sleep(10);
                                                } while (newfax.status == null);
                                                Logger("Id serveur du fax : " + newfax.body + ", Id SendFax : " + newfax.Id);
                                                IO.File.Delete(FI);
                                                this.Invoke(_AddFax, newfax);
                                                sended = true;
                                                Logger("Envoi OK");
                                            }
                                        }
                                    }
                                    else
                                    {
                                        zf_err = "HostName non trouvé pour le fichier joint";
                                        sended = false;
                                    }
                                    if (!sended)
                                    {
                                        ini.StockerValeur("Envoi", "Erreur", zf_err, FI);
                                        Logger("Envoi échoué : " + zf_err);
                                        if (IO.File.Exists(FI + ".bad")) IO.File.Delete(FI + ".bad");
                                        IO.File.Move(FI, FI + ".bad");
                                    }
                                }
                            }
                        }
                    }
                    // On met à jour le status des fax
                    if(zf.CheckNewStatus())
                        maj_state();
                    Threading.Thread.Sleep(TimerDelay);
                }
                Logger("Fin du thread 1");
            }
    maj_state est la procédure qui vérifie le statut de chaque fax :

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
            private void maj_state()
            {
                string f_oldstate="";
                int max = faxes.Count-1;
                fax newfax;
     
                for (int i = max ; i >= 0; i--)
                {
                    if (Tcancel) break;
                    newfax = faxes[i];
                    f_oldstate = newfax.status;
                    zf.GetInfosFax(true, ref newfax, out zf_err);
                    if (newfax.status == null |
                        ((DateTime.Now - newfax.dateajout).TotalDays > config.histo_jours) & config.histo_jours > 0)
                    {
                        Logger("fax " + newfax.body + " ( id = " + newfax.Id + " ) plus disponible ou trop ancien, suppression de la liste");
                        // int n = RetreiveFaxIndex(f);
                        Logger("Index du fax dans la liste : " + i);
                        RemoveFax(i, true);
                    }
                    else
                    {
                        if (!f_oldstate.Equals(newfax.status))
                        {
                            switch (newfax.status.ToUpper())
                            {
                                case "OK":
                                case "FAILED":
                                    if (!newfax.RetourAs400 & retourftp)
                                    {
                                        Logger("Retour AS400 pour le fax " + newfax.body);
                                        if (!AS400.sendretourfax_batch(
                                            config.FTP_user,
                                            config.FTP_pass,
                                            config.FTP_ip,
                                            "LAB400EDT.LIB",
                                            "FAXJRL",
                                            AS400.CreateRetFile(newfax), out zf_err))
                                        {
                                            this.Invoke(new MethodInvoker(delegate()
                                            {
                                                //MessageBox.Show("Un problème FTP est survenu lors du retour vers l'ISeries." + Environment.NewLine +
                                                // "Les retours sont désactivés tant que " + Application.ProductName + " ne sera pas redémarré." + Environment.NewLine + Environment.NewLine +
                                                // "Erreur FTP : " + zf_err, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                                                this.Text = Application.ProductName + " v" + Application.ProductVersion + " - Retour FTP en erreur";
                                            }));
                                            retourftp = false;
                                        }
                                        else
                                        {
                                            newfax.RetourAs400 = true;
                                        }
                                    }
                                    break;
                            }
                            faxes[i] = newfax;
                            this.Invoke(UpdaterState, faxes[i].status, i);
                        }
                    }
                }
            }
    Le type 'fax' est une structure publique :

    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
     
        public struct fax
        {
            public Guid Id;
            public DateTime dateajout;
            public string body;
            public string From;
            public string[,] to;
            public string[] files;
            public string status;
            public string Dossier;
            public string FaxPatient;
            public string CodeMedecin;
            public bool RetourAs400;
        }
    En gros, mon programme au lancement consomme environ 12 K, je me retrouve avec une conso de 200 000 K au bout d'une demi journée d'utilisation.
    Les procédures liées à l'instance 'zf' ne sont selon moi pas en cause.

    Voici les procédures liées au traitement du listView :

    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
    34
    35
    36
     
            void listfax_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
            {
                if (listeCache != null && e.StartIndex >= firstitem && e.EndIndex <= firstitem + listeCache.Count)
                {
                    return;
                }
     
                firstitem = e.StartIndex;
                int length = e.EndIndex - e.StartIndex + 1;
                listeCache = new List<ListViewItem>();
                for (int n = 0; n < length; n++)
                {
                    listeCache.Add(FaxToListe(faxes[e.StartIndex + n]));
                }
            }
     
            void listfax_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
            {
                try
                {
                    if (listeCache != null && e.ItemIndex >= firstitem && e.ItemIndex < firstitem + listeCache.Count)
                    {
                        e.Item = listeCache[e.ItemIndex - firstitem];
                    }
                    else
                    {
                        e.Item = FaxToListe(faxes[e.ItemIndex]);
                    }
                }
                catch (ArgumentOutOfRangeException)
                {
                    Logger("Item " + e.ItemIndex + " n'existe plus.");
                    e.Item = null;
                }
            }
    Vraiment, si je demande de l'aide sur le forum c'est que je sèche totalement sur cette consommation mémoire abusive, j'ai consulté plusieurs sites pour me familiariser avec la gestion mémoire en .NET mais cela ne m'a pas aidé à solutionner mon problème.

    Si vous avez besoin d'autres infos sur mon code ou sur le programme, faites-le moi savoir.

  2. #2
    Membre Expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net Architect
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Par défaut
    Il y a un memory profiler dans vs, essaye avec ça : http://dotnet.dzone.com/articles/pro...ation-visual-1

  3. #3
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Hello,
    les structs sont des types valeur, ce qui signifie qu'à chaque affectation, c'est tout leur contenu qui est copié. Fais de 'fax' une class plutôt qu'une struct, et ça ira déjà beaucoup mieux.

  4. #4
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2006
    Messages
    256
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 256
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Hello,
    les structs sont des types valeur, ce qui signifie qu'à chaque affectation, c'est tout leur contenu qui est copié. Fais de 'fax' une class plutôt qu'une struct, et ça ira déjà beaucoup mieux.
    Ok mais quelque chose m'échappe quand même. On est bien d'accord que lorsqu'une structure n'est plus utilisée ou écrasée par une nouvelle instance, le contenu de celle-ci est rejeté de la pile et remplacé par la nouvelle valeur ?

    Donc dans ma boucle, quand je fais un 'new fax()' ça ne devrait pas engendrer plus de mémoire allouée.

  5. #5
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    Citation Envoyé par Shypster Voir le message
    Ok mais quelque chose m'échappe quand même. On est bien d'accord que lorsqu'une structure n'est plus utilisée ou écrasée par une nouvelle instance, le contenu de celle-ci est rejeté de la pile et remplacé par la nouvelle valeur ?

    Donc dans ma boucle, quand je fais un 'new fax()' ça ne devrait pas engendrer plus de mémoire allouée.
    C'est pas parce qu'un objet n'est plus utilisé que la mémoire est libérée. La mémoire est libérée lorsque c'est nécessaire et que le Garbage Collector s'affaire.

  6. #6
    Expert confirmé Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Par défaut
    un 'MyFax=new fax()' ça ne devrait pas engendrer plus de mémoire allouée
    Sauf si Myfax a été auparavant passé à un traitement qui conserve Myfax ou une copie.

    J'ai l'impression que les fax sont traités dans threads différents et qu'une fois le traitement effectué dans un thread, ce thread ne libère pas systématiquent le fax traité (ou sa copie puisqu'il s'il s'agit d'une structurs).

  7. #7
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2006
    Messages
    256
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 256
    Par défaut
    Citation Envoyé par GuruuMeditation Voir le message
    Il y a un memory profiler dans vs, essaye avec ça : http://dotnet.dzone.com/articles/pro...ation-visual-1
    Malheureusement je ne bosse que sur la version professionnelle de Visual Studio 2010 donc pas de profiling à ma connaissance.

Discussions similaires

  1. besoin d'aide sur trigger
    Par devalender dans le forum SQL
    Réponses: 2
    Dernier message: 18/07/2004, 22h28
  2. [D7] Besoin d'aide sur un PChar
    Par bobby-b dans le forum Langage
    Réponses: 6
    Dernier message: 30/06/2004, 16h42
  3. Filemaker ... besoin d'aide sur les Plugin
    Par joange dans le forum Autres SGBD
    Réponses: 3
    Dernier message: 22/04/2004, 10h16
  4. [intermedia] besoin d'aide sur script PL/SQL
    Par SteelBox dans le forum PL/SQL
    Réponses: 8
    Dernier message: 05/01/2004, 19h59
  5. [CR] besoin d'aide sur les formules
    Par GuillaumeDSA dans le forum Formules
    Réponses: 4
    Dernier message: 10/07/2003, 12h19

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