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

MFC Discussion :

[MFC] Problème de mémoire lors de l'exécution d'une application


Sujet :

MFC

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 8
    Points : 5
    Points
    5
    Par défaut [MFC] Problème de mémoire lors de l'exécution d'une application
    Salut,

    J'ai développé un programme sous Visual C++ qui utilise les éléments de la classe CDC (classe pour dessiner dans l'application). Quand je lance l'éxécutable, au bout d'une cinquantaine de minutes, mon programme plante !
    J'ai regardé d'où pouvait venir mon problème et ... j'ai un élément de réponse : quand je lance le gestionnaire de tâches de Windows, je constate que l'espace mémoire utilisée par mon application augmente de 4KiloOctets de façon régulière (ce qui, au cumulé de l'éxecution de mon application, mon programme plante !)
    Dans mon programme, j'appelle toutes les 2 secondes la fonction suivante dans un thread :
    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
    void CMyApp::DrawLongitudinalAxis(CStatic* area,int min,int max,char nbraxis)
    {
    	CDC* ChartCDC;	//Déclaration d'un Device Context
    	CRect ChartRect;//Déclaration d'un rectangle englobant
    	CPen aPen;	//Déclaration d'une plume
    	CString Etiquette;//Déclaration d'une variable de type String
     
    	area->Invalidate(TRUE);
     
    	ChartCDC = area->GetDC();		//Affectation de la zone de dessin à la variable ChartCDC
    	area->GetClientRect(&ChartRect);	//Affectation du rectangle englobant du graphique à la variable area
    	ChartRect.DeflateRect(1,1);
    	ChartCDC->SetBkMode(TRANSPARENT);
    	ChartCDC->SetTextAlign(TA_LEFT);
    	aPen.CreatePen(PS_DASHDOT,1,RGB(255,0,0));	
    	ChartCDC->SelectObject(&aPen);
     
    	ChartCDC->MoveTo(0,ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1)));
    	ChartCDC->LineTo(ChartRect.Width(),ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1)));
    	Etiquette.Format("%.0f",(float)5*(max-min)/(nbraxis-1)+min);
    	ChartCDC->TextOut(0,ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1))-7,Etiquette);
     
    	aPen.DeleteObject();
    	ChartCDC->ReleaseOutputDC();
    	area->ReleaseDC(ChartCDC);
    }
    Je suis sûr que mon problème vient de là car quand j'enlève l'éxecution de cette fonction toutes les 2 secondes, mon programme ne plante pas et l'espace mémoire utilisé par mon application n'augmente pas.

    C'est la première fois que je rencontre un problème de ce genre et je remercie d'avance tout ceux qui pourront m'aider.

  2. #2
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    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 361
    Points : 20 381
    Points
    20 381
    Par défaut
    Il ya de fortes chances que des objets GDI soient mal effacés je dirais 90% de chances.
    Donc vérifier tous les SelectObject/DeleteObject les créations de HDC et ReleaseDC

  3. #3
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Je confirme ce que Mat.M a dit.

    Il faut d'abord déselectionner l'objet sinon le DeleteObject() echoue ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    CPen *pOldPen=ChartCDC->SelectObject(&aPen); // selection
     
    ...
     
    ChartCDC->SelectObject(pOldPen);  // déselection = selection de l'ancien stylo
    aPen.DeleteObject();           // facultatif, le destructeur de CPen s'en charge ...
    @+

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Merci Mat.M & stephdim pour votre réponse

    J'ai fais les modifications comme tu me l'as indiqué stephdim et... au premier abord, cela n'avais pas résolu mon problème : l'espace mémoire utilisé par mon programme continuait d'augmenter régulièrement de 4KiloOctets et au bout d'une cinquantine de minutes, le programme plantait.
    J'ai essayer toutes les fonctions possibles pour résoudre le problème et j'en arrive au code suivant :
    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
    void CMyApp::DrawLongitudinalAxis(CStatic* area,int min,int max,char nbraxis)
    {
    	CDC* ChartCDC;	//Déclaration d'un Device Context
    	CRect ChartRect;//Déclaration d'un rectangle englobant
    	CPen aPen;	//Déclaration d'une plume
    	CString Etiquette;//Déclaration d'une variable de type String
     
    	area->Invalidate(TRUE);
     
    	ChartCDC = area->GetDC();		//Affectation de la zone de dessin à la variable ChartCDC
    	area->GetClientRect(&ChartRect);	//Affectation du rectangle englobant du graphique à la variable area
    	ChartRect.DeflateRect(1,1);
    	ChartCDC->SetBkMode(TRANSPARENT);
    	ChartCDC->SetTextAlign(TA_LEFT);
    	aPen.CreatePen(PS_DASHDOT,1,RGB(255,0,0));	
    	CPen *pOldPen=ChartCDC->SelectObject(&aPen);
     
    	ChartCDC->MoveTo(0,ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1)));
    	ChartCDC->LineTo(ChartRect.Width(),ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1)));
    	Etiquette.Format("%.0f",(float)5*(max-min)/(nbraxis-1)+min);
    	ChartCDC->TextOut(0,ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1))-7,Etiquette);
     
    	ChartCDC->SelectObject(&pOldPen);  // déselection = selection de l'ancien stylo	
    	aPen.DeleteObject();
    //	ChartCDC->ReleaseOutputDC();	<<==Sans effets sur la libération d'espace mémoire
    //	area->ReleaseDC(ChartCDC);	<<==Pareil
    	ReleaseDC(ChartCDC);	//Çà apparemment çà marche !
    }
    Avec ce code là, j'ai tester mon programme pendant un peu plus d'une heure et demi sans qu'il ne plante.
    Cependant, avec le gestionnaire de tâches de Windows je constate que l'espace mémoire utilisé par mon programme augmente quand même (mais beaucoup moins vite qu'avant).
    Y a-t-il un moyen d'être sûr que l'espace mémoire est libérer ? J'ai essayé : while(ReleaseDC(ChartCDC)==0); mais çà buggue d'entré !

  5. #5
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Si tu fais:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ChartCDC = area->GetDC();
    alors tu dois faire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    area->ReleaseDC(ChartCDC);
    Bug ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ChartCDC->SelectObject(&pOldPen);
    enleve le & devant (ça m'etonne que ça compile)

    Sinon le reste me parait correcte

    sauf que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    area->Invalidate(TRUE);
    ça m'étonne que tu arrives à voir ton dessin, puisque tu invalides ce que tu viens de dessiner (le prochain WM_PAINT reeffacera tout), mais là c'est hors sujet ...

    Si t'as encore des memory leaks, c'est que ça vient d'ailleurs ...

    @+

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    C'est super sympa de ta part stephdim.

    Je vais apporter au programme les rectifications que tu m'as donné et je te tiens au courant.

    Ou sinon, pour l'histoire de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    area->Invalidate(TRUE);
    En fait, j'invalide ma zone de dessin car je redessine dessus : çà me permet de faire un petit effet d'animation

  7. #7
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Tu invalides ton controle static --> donc tu vas générer un message WM_PAINT qui sera pris en compte que quand la file de message sera vide

    Tu dessines dans la foulée (juste apres le Invalidate) dans la zone client du static

    Et là le WM_PAINT arrive ... ça devrait effacer ton dessin

    Pour ton prob de GetDC(), ReleaseDC(), tu peux utiliser:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    CClientDC dc(area);
    dc.SelectObject(...)
    dc ....
    l'avantage : pas besoin de se preoccuper de liberer le Device Context, c'est le destructeur de CClientDC qui s'en occupe.
    L'inconvénient : une exception est lancée (AfxThrowResourceException()) s'il n'y a pas de Device Context disponible, mais je ne pense pas que ça soit genant pour ton appli.

    @+

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Je vais tester tout çà et je te tiens au courant.

    Merci encore pour ton aide stephdim

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Merci stephdim,...

    C'est super-sympa,... ta dernière solution à mon problème s'avère être très concluante !!!
    J'ai plus mon problème d'augmentation de l'espace mémoire utilisé par le programme. Maintenant, je ne vais pas arréter d'utiliser des CClientDC au lieu des CDC !!!

    Le code qui marche est le suivant :
    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
    void CMyApp::DrawLongitudinalAxis(CStatic* area,int min,int max,char nbraxis)
    {
    	CClientDC ChartCDC(area);	//Déclaration d'un Device Context
    	CRect ChartRect;		//Déclaration d'un rectangle englobant
    	CPen aPen;			//Déclaration d'une plume
    	CString Etiquette;		//Déclaration d'une variable de type String
     
    	area->Invalidate(TRUE);
     
    	area->GetClientRect(&ChartRect);	//Affectation du rectangle englobant du graphique à la variable area
    	ChartRect.DeflateRect(1,1);
    	ChartCDC.SetBkMode(TRANSPARENT);
    	ChartCDC.SetTextAlign(TA_LEFT);
    	aPen.CreatePen(PS_DASHDOT,1,RGB(255,0,0));	
    	CPen *pOldPen=ChartCDC.SelectObject(&aPen);
     
    	ChartCDC.MoveTo(0,ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1)));
    	ChartCDC.LineTo(ChartRect.Width(),ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1)));
    	Etiquette.Format("%.0f",(float)5*(max-min)/(nbraxis-1)+min);
    	ChartCDC.TextOut(0,ChartRect.Height()-5*(ChartRect.Height()/(nbraxis-1))-7,Etiquette);
     
    	ChartCDC.SelectObject(pOldPen);  // déselection = selection de l'ancien stylo	
    	aPen.DeleteObject();
    }

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 09/02/2012, 22h52
  2. Réponses: 5
    Dernier message: 09/02/2012, 19h29
  3. Réponses: 8
    Dernier message: 28/09/2011, 16h18
  4. [AC-2003] Message derreur lors de l'exécution d'une application Access
    Par BahloulBrahim dans le forum Access
    Réponses: 7
    Dernier message: 07/07/2010, 16h53
  5. Exception lors de l'exécution d'une application RCP
    Par bricelaurel dans le forum Eclipse Platform
    Réponses: 0
    Dernier message: 21/10/2008, 16h06

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