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 :

Problème de libération de la mémoire virtuelle


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre du Club
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Février 2013
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2013
    Messages : 7
    Par défaut Problème de libération de la mémoire virtuelle
    Bonjour à tous,

    Mon problème est le suivant.
    J'ai réalisé une application en C++ sous Visual Studio 10 sous windows XP 32bit.
    Cette application doit créer une quantité très importante d'objets en mémoire de petite taille (environ 20 Ko).
    J'ai donc ajouté à mon code un bloc try/catch pour intercepter les dépassements mémoires.
    Lorsque l'occupation mémoire atteint 2Go, les allocations échouent. Une exception est générée. L'application la capture et libère la mémoire.
    L'objectif est de pouvoir gérer ces situations et garder la stabilité de l'appli.
    Or il semble qu'après avoir libérer toutes les ressources allouées par l'application, la mémoire virtuelle n'est pas libérée.
    En utilisant la fonction GlobalMemoryEx(), on s'apperçoit que la mémoire disponible n'est que de quelques méga.
    Il est ensuite impossible de réallouer un espace mémoire de plus d'une dizaine de méga.

    Pour mieux comprendre voici un code d'exemple reproduisant le problème :

    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
    // AllocationErr.cpp : définit le point d'entrée pour l'application console.
    //
     
    #include "stdafx.h"
    //#include <iostream.h> 
    #include <vector> 
    #include "AllocationErr.h"
     
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
     
    using namespace std;
     
    void ReportMemory()
    {
    	MEMORYSTATUSEX statex;
     
    	statex.dwLength = sizeof (statex);
    	GlobalMemoryStatusEx (&statex);
     
    	HANDLE heap = GetProcessHeap();
    	SIZE_T size =  HeapCompact(heap, 0);
     
    	BOOL validated = HeapValidate(heap, 0, NULL);
     
    	TRACE("GlobalMemoryStatusEx:\n");
    	TRACE(" + TotalVirtual : %0.1lf Mo\n", statex.ullTotalVirtual / (1024.0 * 1024.0));
    	TRACE(" + AvailVirtual : %0.1lf Mo\n", statex.ullAvailVirtual / (1024.0 * 1024.0));
    	TRACE(" + Process mem load : %0.1lf %%\n", (1.0 - (double) statex.ullAvailVirtual / (double) statex.ullTotalVirtual) * 100.0);
    	TRACE(" + TotalPageFile : %0.1lf Mo\n", statex.ullTotalPageFile / (1024.0 * 1024.0));
    	TRACE(" + AvailPageFile : %0.1lf Mo\n", statex.ullAvailPageFile / (1024.0 * 1024.0));
    }
     
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
        TRACE("Before allocation\n");
        ReportMemory();
     
        const unsigned int taille_bloc = 10* 1024, nb_blocs_max = (3U * 1024U * 1024U * 1024U / taille_bloc);
        int i = 0;
     
        char ** p = NULL;
     
        try
        {
            p = new char *[nb_blocs_max];
     
            memset(p, 0, nb_blocs_max * sizeof(char *));
     
            for(i = 0; i < nb_blocs_max; i++)
            {
                p[i] = new char[taille_bloc];
            }
        }
        catch (CMemoryException* e)
        {
            e->Delete();
     
            TRACE("After the program ran out of memory\n");
            ReportMemory();
     
            for(i = 0; i < nb_blocs_max; i++)
            {
                if(p[i])
                {
                    delete [] p[i];
                }
            }
     
            delete [] p;
        }
     
        TRACE("After freeing memory\n");
        ReportMemory();
     
        char * t = NULL;
        try
        {
            const unsigned int taille_max = 30 * 1024 * 1024;
            t = new char[taille_max];
        }
        catch (CMemoryException* e)
        {
            TRACE("Memory allocation failed\n");
            e->Delete();
     
            if(t)
            {
                delete [] t;
            }
        }
     
        return 0;
    }

    Le résultat afficher est le suivant :

    Before allocation
    GlobalMemoryStatusEx:
    + TotalVirtual : 2047.9 Mo
    + AvailVirtual : 2016.8 Mo
    + Process mem load : 1.5 %
    + TotalPageFile : 5198.6 Mo
    + AvailPageFile : 3172.9 Mo

    After the program ran out of memory
    GlobalMemoryStatusEx:
    + TotalVirtual : 2047.9 Mo
    + AvailVirtual : 4.5 Mo
    + Process mem load : 99.8 %
    + TotalPageFile : 5198.6 Mo
    + AvailPageFile : 1155.2 Mo

    After freeing memory
    GlobalMemoryStatusEx:
    + TotalVirtual : 2047.9 Mo
    + AvailVirtual : 5.7 Mo
    + Process mem load : 99.7 %
    + TotalPageFile : 5198.6 Mo
    + AvailPageFile : 3170.8 Mo


    Avez vous une idée ?
    Vous trouverez également en pièce jointe le projet Visual 10 ...
    Fichiers attachés Fichiers attachés

  2. #2
    Membre éclairé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Par défaut
    Plusieurs remarques:

    * pourquoi ce melange de C et C++ ?
    * attention, Windows ne respecte pas la casse mais d'autres système si, donc ton code ne compilera pas sous Linux par exemple, notamment à cause de "Ressource.h" qui est inclus en temps que "ressource.h".
    * j'ai regardé vite fais mais j'ai l'impression que tu libères la mémoire uniquement si une exeption est levée.
    * juste pour info, où est définie "MEMORYSTATUSEX" ?
    * attention quand tu fais "memset(p, 0, nb_blocs_max * sizeof(char *));" car sizeof(char *) = taille d'un pointeur de char en octet.

  3. #3
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Bonjour et bienvenue sur le forum

    Pourquoi ne pas avoir tout simplement une politique de gestion de la mémoire qui n'attend pas que la mémoire soit saturée avant de libérer les ressources inutilisés ?

  4. #4
    Membre du Club
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Février 2013
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2013
    Messages : 7
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Bonjour et bienvenue sur le forum

    Pourquoi ne pas avoir tout simplement une politique de gestion de la mémoire qui n'attend pas que la mémoire soit saturée avant de libérer les ressources inutilisés ?
    Bonjour,

    Dans mon cas j'utilise des fonctions issues de bibliothèques que je ne maitrise pas et qui créent des objets en mémoire dont je ne connais pas forcément la taille auparavant ... Et malheureusement c'est à moi de gérer le tout ...

  5. #5
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Ça sent un problème de fragmentation mémoire à plein nez.

    Le code que tu as donné initialement reproduit exactement le problème, y compris en release ? Ou c’est seulement un exemple ?

  6. #6
    Membre du Club
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Février 2013
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2013
    Messages : 7
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Ça sent un problème de fragmentation mémoire à plein nez.

    Le code que tu as donné initialement reproduit exactement le problème, y compris en release ? Ou c’est seulement un exemple ?
    Après vérification, le code reproduit le même problème en Release et en Debug.
    J'ai également pensé à un problème de fragmentation. Mais lorsque je libère la mémoire dans mon exemple, la documentation windows dit que le tas est "recompacté". Je suppose qu'il défragmente automatiquement le mémoire. Je n'ai pas trouvé de fonction de l'API Windows permettant de réaliser manuellement cette opération ...

  7. #7
    Membre chevronné
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Par défaut
    Je serais curieux de savoir ce qui se passe si tu réecris ton programme en utilisant malloc()/free() plutôt que new[] delete[].
    evidemment, malloc() ne generera pas d'exception donc il faudra plutôt tester sa valeur de retour, le programme ne peut pas fonctionner de la même manière.

  8. #8
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 540
    Par défaut
    Citation Envoyé par Martial72 Voir le message
    Après vérification, le code reproduit le même problème en Release et en Debug.
    J'ai également pensé à un problème de fragmentation. Mais lorsque je libère la mémoire dans mon exemple, la documentation windows dit que le tas est "recompacté". Je suppose qu'il défragmente automatiquement le mémoire. Je n'ai pas trouvé de fonction de l'API Windows permettant de réaliser manuellement cette opération ...
    salut je pense que c'est une des explications au problème
    Sinon sous Windows XP il y a le fichier pagefile.sys,je suppose que c'est un fichier de "swap"
    Si tu fais des grosses allocations,l'OS écrit dedans.
    Le fait de fermer ton programme ne désalloue pas forcément les écritures dans pagefile.sys

    http://support.microsoft.com/kb/99768/en-us

  9. #9
    Membre du Club
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Février 2013
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2013
    Messages : 7
    Par défaut
    Citation Envoyé par LinuxUser Voir le message
    Plusieurs remarques:

    * pourquoi ce melange de C et C++ ?
    * attention, Windows ne respecte pas la casse mais d'autres système si, donc ton code ne compilera pas sous Linux par exemple, notamment à cause de "Ressource.h" qui est inclus en temps que "ressource.h".
    * j'ai regardé vite fais mais j'ai l'impression que tu libères la mémoire uniquement si une exeption est levée.
    * juste pour info, où est définie "MEMORYSTATUSEX" ?
    * attention quand tu fais "memset(p, 0, nb_blocs_max * sizeof(char *));" car sizeof(char *) = taille d'un pointeur de char en octet.
    Le C++ étant dérivé du C, il est normal que l'on retrouve du C dans du code C++. Mais là n'est pas le problème. Il s'agit d'un problème purement Windows et notamment Windows XP 32 bits. J'ai ajouté le projet dans un zip si besoin.

    MEMORYSTATUSE est une structure standard de l'API windows.

    l'instruction "memset(p, 0, nb_blocs_max * sizeof(char *));" est correcte car il s'agit d'un tableau de pointeur char. L'objectif est ici de stresser le gestionnaire de mémoire en allouant une multitude de blocs de quelques méga que l'on stocke dans le tableau.

    La désallocation est en effet réalisée dans le cas où l'exception pète. Mais dans mon exemple, elle pète forcément (car il s'agit juste d'un exemple pour montrer le défaut)

    Voilà ... si quelqu'un à une idée, je suis prenneur ...

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par Martial72 Voir le message
    Le C++ étant dérivé du C, il est normal que l'on retrouve du C dans du code C++.
    Je ne peux que m'inscrire en faux intégral sur ce passage!!!

    S'il est vrai que C++ "hérite" de C, ce sont deux langages qui n'ont plus rien à voir, et il serait plus que temps que les gens commencent tout doucement à l'assimiler!

    A l'heure actuelle, le seul cas dans lequel il est envisageable de mélanger C et C++, c'est si tu dois t'interfacer avec une bibliothèque ou une interface C.

    En dehors de ce cas, tu ne devrais absolument jamais mélanger les deux dans un fichier ou dans une fonction. Rien ne t'empêche d'avoir des fichiers C et des fichiers C++ dans un seul et même projet, bien que je déconseille malgré tout cette pratique, mais, si tu écris du code C++, tu as plus qu'intérêt à n'utiliser que C++

    Cela aurait, entre autre, l'intérêt de te permettre d'utiliser pleinement le RAII (Ressource Acquisition Is Initialisation) même si, en l'occurrence, c'est surtout l'effet inverse qui t'intéresserait
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Bonjour,
    Le code a l'air correct. (mais je n'ai pas pu tester avec mon VS2010 express qui ne supporte pas les MFC)
    Citation Envoyé par Martial72 Voir le message
    Or il semble qu'après avoir libérer toutes les ressources allouées par l'application, la mémoire virtuelle n'est pas libérée.
    En utilisant la fonction GlobalMemoryEx(), on s'apperçoit que la mémoire disponible n'est que de quelques méga. Il est ensuite impossible de réallouer un espace mémoire de plus d'une dizaine de méga.
    Je n'ai pas compris comment tu détermines qu'il est "ensuite impossible de réallouer un espace mémoire de plus d'une dizaine de méga". Tu as essayé d'afficher le numéro de bloc qui provoque l'exception dans les deux cas ?

  12. #12
    Membre du Club
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Février 2013
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2013
    Messages : 7
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Bonjour,
    Le code a l'air correct. (mais je n'ai pas pu tester avec mon VS2010 express qui ne supporte pas les MFC)

    Je n'ai pas compris comment tu détermines qu'il est "ensuite impossible de réallouer un espace mémoire de plus d'une dizaine de méga". Tu as essayé d'afficher le numéro de bloc qui provoque l'exception dans les deux cas ?
    Bonjour,

    Dans la dernière partie du code je réalloue 30 Méga dans le pointeur t.
    L'allocation échoue à tous les coups, alors que je viens de libérer la totalité de la mémoire allouée ...

    Remarque En utilisan ProcessExplorer, je peux voir que la mémoire privée de l'application a été libérée mais en regardant la mémoire virtuelle, on s'apperçoit qu'elle est toujours à 2 Go d'occupation (et ce même après avoir libéré la mémoire). ???

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

Discussions similaires

  1. Problème de libération de la mémoire dans une fonction
    Par ArnaudFu1 dans le forum Débuter
    Réponses: 2
    Dernier message: 23/02/2012, 16h21
  2. [C] [libxml] problème de libération de la mémoire
    Par radouane_as dans le forum XML
    Réponses: 3
    Dernier message: 16/01/2008, 10h58
  3. [Debutant(e)]problème de libération de mémoire
    Par skywalker3 dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 10/02/2005, 17h38
  4. Problème avec la mémoire virtuelle
    Par Anonymous dans le forum CORBA
    Réponses: 13
    Dernier message: 16/04/2002, 16h10

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