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 :

Gestionnaire de mémoire


Sujet :

C++

  1. #1
    Membre habitué
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Février 2009
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 141
    Points : 195
    Points
    195
    Par défaut Gestionnaire de mémoire
    Salut,

    J'ai un problème avec un gestionnaire de mémoire que je tire de celui de Laurent Gomila trouvé sur cette page

    Il fonctionne parfaitement lorsque j'utilise seulement un new, mais dès que je met un delete il semble tourner en boucle sur la surcharge de l'opérateur delete

    Voici tous les fichiers du projet sous codeblocks :
    http://www.megaupload.com/?d=EVK7304V

    Rencontrez-vous le même problème? Et surtout, savez-vous comment le corriger?

    J'ai demandé au créateur qui m'a répondu qu'il n'avait jamais eu ce problème, donc je me demande ce que j'ai dans le code qui fait planter tout ça.

    Merci d'avance

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Le mieux est encore que tu reproduises le bug sur un exemple très simplifié et que tu nous montres le code qui pose problème.

  3. #3
    Membre habitué
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Février 2009
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 141
    Points : 195
    Points
    195
    Par défaut
    Le bug est reproduit dans le pack, il y a plusieurs fichiers pour le projet.

    Mais voila un exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <iostream>
    #include "Debug/On.h"
     
    using namespace std;
     
    int main()
    {
        int* test = new int;
        return 0;
    }
     
    #include "Debug/Off.h"
    Fonctionne sans problème

    Mais dès que j'ose utiliser un delete :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <iostream>
    #include "Debug/On.h"
     
    using namespace std;
     
    int main()
    {
        int* test = new int;
        delete test;
        return 0;
    }
     
    #include "Debug/Off.h"
    L'application se lance, et se ferme (se fait fermer il semblerait).

    D'après le débugger, le code tourne en boucle sur la surcharge de delete.

    Voici le fichier qui surcharge les méthodes new et delete (Debug/On.h) :

    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
    #ifdef _DEBUG
     
    #ifndef DEBUGNEW_H
    #define DEBUGNEW_H
     
    #include "MemoryManager.h"
     
    inline void* operator new(std::size_t Size, const char* File, int Line)
    {
        return MemoryManager::Instance().Allocate(Size, File, Line, false);
    }
     
    inline void* operator new[](std::size_t Size, const char* File, int Line)
    {
        return MemoryManager::Instance().Allocate(Size, File, Line, true);
    }
     
    inline void operator delete(void* Ptr)
    {
        MemoryManager::Instance().Free(Ptr, false);
    }
     
    inline void operator delete(void* Ptr, const char* File, int Line)
    {
        MemoryManager::Instance().NextDelete(File, Line);
        MemoryManager::Instance().Free(Ptr, false);
    }
     
    inline void operator delete[](void* Ptr)
    {
        MemoryManager::Instance().Free(Ptr, true);
    }
     
    inline void operator delete[](void* Ptr, const char* File, int Line)
    {
        MemoryManager::Instance().NextDelete(File, Line);
        MemoryManager::Instance().Free(Ptr, true);
    }
     
    #endif // DEBUGNEW_H
     
    #ifndef new
        #define new    new(__FILE__, __LINE__)
        #define delete MemoryManager::Instance().NextDelete(__FILE__, __LINE__), delete
    #endif
     
    #endif
    Les autres fichiers sont dans le pack :
    MemoryManager.h :
    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
    #ifndef MEMORYMANAGER_H_INCLUDED
    #define MEMORYMANAGER_H_INCLUDED
     
    #include <iostream>
    #include <iomanip>
    #include <map>
    #include <stack>
    #include <string>
     
    class MemoryManager
    {
        public:
            static MemoryManager& Instance();
            void* Allocate(std::size_t Size, std::string File, int Line, bool Array);
            void Free(void* Ptr, bool Array);
            void NextDelete(std::string File, int Line);
     
        private:
            MemoryManager();
            ~MemoryManager();
            void ReportLeaks();
     
            struct TBlock
            {
                std::size_t Size;
                std::string File;
                int         Line;
                bool        Array;
            };
            typedef std::map<void*, TBlock> TBlockMap;
     
            TBlockMap          m_Blocks;
            std::stack<TBlock> m_DeleteStack;
     
    };
     
    #endif // MEMORYMANAGER_H_INCLUDED
    MemoryManager.cpp :
    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
    96
    97
    98
    99
    100
    101
    102
    103
    #include "MemoryManager.h"
     
    MemoryManager::MemoryManager()
    {
        std::cout << "  ========================================" << std::endl;
        std::cout << "             Memory leak tracker          " << std::endl;
        std::cout << "  ========================================" << std::endl << std::endl;
    }
     
    MemoryManager::~MemoryManager()
    {
        if (m_Blocks.empty())
        {
            std::cout << std::endl;
            std::cout << "  ========================================" << std::endl;
            std::cout << "     No leak detected, congratulations !  " << std::endl;
            std::cout << "  ========================================" << std::endl;
        }
        else
        {
            std::cout << std::endl;
            std::cout << "  ========================================" << std::endl;
            std::cout << "   Oops... Some leaks have been detected  " << std::endl;
            std::cout << "  ========================================" << std::endl;
            std::cout << std::endl;
     
            ReportLeaks();
        }
    }
     
    MemoryManager& MemoryManager::Instance()
    {
        static MemoryManager Inst;
     
        return Inst;
    }
     
    void MemoryManager::ReportLeaks()
    {
        std::size_t TotalSize = 0;
        for (TBlockMap::iterator i = m_Blocks.begin(); i != m_Blocks.end(); ++i)
        {
            TotalSize += i->second.Size;
     
            std::cout << "-> 0x" << i->first
                   << " | "   << std::setw(7) << std::setfill(' ') << static_cast<int>(i->second.Size) << " octets"
                   << " | "   << i->second.File << " (" << i->second.Line << ")" << std::endl;
     
            free(i->first);
        }
     
        std::cout << std::endl << std::endl << "-- "
               << static_cast<int>(m_Blocks.size()) << " blocs non-libéré(s), "
               << static_cast<int>(TotalSize)       << " octets --"
               << std::endl;
    }
     
    void* MemoryManager::Allocate(std::size_t Size, std::string File, int Line, bool Array)
    {
        void* Ptr = malloc(Size);
     
        TBlock NewBlock;
        NewBlock.Size  = Size;
        NewBlock.File  = File;
        NewBlock.Line  = Line;
        NewBlock.Array = Array;
        m_Blocks[Ptr]  = NewBlock;
     
        return Ptr;
    }
     
    void MemoryManager::Free(void* Ptr, bool Array)
    {
        TBlockMap::iterator It = m_Blocks.find(Ptr);
     
        if (It == m_Blocks.end())
        {
            free(Ptr);
            return;
        }
     
        if (It->second.Array != Array)
        {
            std::cout << "BadDelete error !" << std::endl;
            std::cout << It->second.File << ":" << It->second.Line << std::endl;
            std::cout << (int) !Array << std::endl;
            return;
        }
     
        m_Blocks.erase(It);
        m_DeleteStack.pop();
     
        free(Ptr);
    }
     
    void MemoryManager::NextDelete(std::string File, int Line)
    {
        TBlock Delete;
        Delete.File = File;
        Delete.Line = Line;
     
        m_DeleteStack.push(Delete);
    }

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    As-tu mis un point d'arrêt à ton destructeur ?
    As-tu mis un point d'arrêt à delete et regarder ce qu'il se passe en mode pas à pas ?

  5. #5
    Membre habitué
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Février 2009
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 141
    Points : 195
    Points
    195
    Par défaut
    La seule chose que j'ai pu tirer du debug c'est que l'instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MemoryManager::Instance().Free(Ptr, false);
    est executée en boucle

    (Cette ligne vient de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline void operator delete(void* Ptr)
    {
        MemoryManager::Instance().Free(Ptr, false);
    }
    Aussi, la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static MemoryManager Inst;
    semble être executée en boucle, mais pas le return Inst;

    Je n'ai jamais vu ça :/

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    -> Rebuild All : t'as essayé ...

  7. #7
    Membre habitué
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Février 2009
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 141
    Points : 195
    Points
    195
    Par défaut
    Le problème n'a rien a voir avec un oubli de compilation ou autre, après le rebuild all, c'est exactement pareil

  8. #8
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    Sous visual ça marche, et sous codeblocks, non...

    J'ai changé l'opérateur delete:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    inline void operator delete(void* Ptr)
    {
        static int i = 0;
        i++;
        if (i > 100)
        {
            std::cout << "stack overflow!" << std::endl;
            exit(1);
        }
        MemoryManager::Instance().Free(Ptr, false);
    }
    Et j'ai un stack overflow malgré un seul delete ^^

    Et il n'y a aucun appel à delete à part dans le main, pas un dans les headers/autres sources. A moins qu'il n'y ait corruption quelque part, je ne vois pas comment c'est possible...

    ----

    Après quelques tests, minGW n'aime pas les variables statiques dans des fonctions de classe statiques...

    Il suffit donc de changer un peu le header:

    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
    class MemoryManager
    {
        public:
            static MemoryManager& Instance();
            void* Allocate(std::size_t Size, std::string File, int Line, bool Array);
            void Free(void* Ptr, bool Array);
            void NextDelete(std::string File, int Line);
     
        /* pas de private sinon impossible d'initialiser la variable statique */
            MemoryManager();
            ~MemoryManager();
     
            void ReportLeaks();
     
            struct TBlock
            {
                std::size_t Size;
                std::string File;
                int         Line;
                bool        Array;
            };
            typedef std::map<void*, TBlock> TBlockMap;
     
            TBlockMap          m_Blocks;
            std::stack<TBlock> m_DeleteStack;
     
    };
     
    /* variable statique */
    MemoryManager __MemMngrinst;
    et la fonction Instance:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    MemoryManager& MemoryManager::Instance()
    {
        return __MemMngrinst;
    }
    Et là ça marche mieux.

    Bien sûr on perd le côté singleton en enlevant le private, mais même en créant plein de classes MemoryManager le comportement du programme ne changera pas

    Au pire il existe des méthodes comme classe amie ou allocation dynamique pour faire un singleton, mais à quoi bon? (dans ce cas-ci hein, pas de troll)

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Aussi, était-ce normal que dans ton code, NextDelete() soit appelé deux fois pour un même delete? (même si tu sembles avoir modifié depuis)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Membre habitué
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Février 2009
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2009
    Messages : 141
    Points : 195
    Points
    195
    Par défaut
    Médinoc : Non nextdelete est appelé une fois pour chaque delete, mais lorsque new rate, un delete est appelé avec les mêmes constructeurs et donc il faut faire le nextdelete qui n'a pas été appelé, tout cela est expliqué dans le tutoriel

    Sinon j'ai appliqué et modifié le code (J'ai mis l'instance dans une variable statique de la classe) et ça marche parfaitement, un grand merci à coyotte507

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

Discussions similaires

  1. Conflit entre mon gestionnaire de mémoire et afxmem
    Par mister3957 dans le forum C++
    Réponses: 9
    Dernier message: 30/06/2008, 12h52
  2. Réponses: 4
    Dernier message: 02/06/2008, 20h12
  3. Réponses: 10
    Dernier message: 20/08/2007, 10h47
  4. gestionnaire de mémoire en c
    Par kagemusha dans le forum C
    Réponses: 13
    Dernier message: 14/10/2006, 11h06
  5. Réponses: 1
    Dernier message: 27/06/2006, 20h28

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