2010-10-12 3 views
4

Si j'ai un programme C++ natif et que je regarde son compteur de mémoire initial "Private bytes" pourquoi ne reviendrait-il pas à sa valeur d'origine après qu'un objet ait été créé puis supprimé? Par exemple si j'ai une application (32 bits, MFC C++ natif) qui a deux boutons. Un dans une boucle qui alloue 1 000 000 instances d'un objet puis l'autre bouton que l'autre supprime ensuite ces mêmes objets. Si je regarde mes compteurs d'octets privés pour le processus, j'ai les 3 valeurs suivantes:
.
Description de .......... Octets privés Nombre
============= =================== ===
App démarré ................. 1,608K
Objets. créé ........ 33,176K
Objets. supprimé .......... 2,520KPourquoi le compteur de mémoire "Private Bytes" d'un processus ne retourne-t-il jamais à sa valeur d'origine?

Fuite de 912K (2520-1608)?

En supposant que mon code ne fuit pas la mémoire, je crois que ce n'est pas la raison pour laquelle les octets privés ne reviennent pas à la valeur initiale EXACT?

Si je clique sur les deux touches (ne pas avoir relancé le programme) (1er bouton crée un autre 1.000.000 objets) et le second les supprime, j'ai ceci:

objets. créé ........ 33,472K
Objets. supprimé .......... 2,552K

Nouvelle fuite de (2552-2520) = 32K

Je suis à la recherche d'une explication sur les raisons de retour la mémoire ne serait pas aller à la valeur orginal .

Exemple de code (certains code généré dépouillé pour réduire le bruit):

class Person 
{ 
public: 
    Person(void); 
    ~Person(void); 

    Person* Next; 
    int A; 
    int B; 
    int C; 
    int D; 

}; 


class Cdelme_MFC2005_MemoryTestDlg : public CDialog 
{ 
// some code stripped out here to simplify reading. 

    Person* m_PeopleList_First; 
    Person* m_PeopleList_Last; 

public: 
    afx_msg void OnBnClickedButtonAllocate(); 
    afx_msg void OnBnClickedButtonFree(); 
}; 


Cdelme_MFC2005_MemoryTestDlg::Cdelme_MFC2005_MemoryTestDlg(CWnd* pParent /*=NULL*/) 
    : CDialog(Cdelme_MFC2005_MemoryTestDlg::IDD, pParent) 
{ 
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 

    m_PeopleList_First = NULL; 
    m_PeopleList_Last = NULL; 

} 


void Cdelme_MFC2005_MemoryTestDlg::OnBnClickedButtonAllocate() 
{ 
    if (m_PeopleList_First == NULL) 
    { 
     m_PeopleList_First = new Person(); 
     m_PeopleList_First->A = 0; 
     m_PeopleList_Last = m_PeopleList_First; 
    } 

    int MAX = 1000000; 
    for (int i = 0; i <MAX ; i++) 
    { 
     Person* p = new Person(); 
     p->A = i; 
     m_PeopleList_Last->Next = p; 
     m_PeopleList_Last = p; 
    } 
} 

void Cdelme_MFC2005_MemoryTestDlg::OnBnClickedButtonFree() 
{ 
    Person* p = m_PeopleList_First; 
    while (p != NULL) 
    { 
     Person* pNext = p->Next; 
     delete p; 
     p = pNext; 
    } 
    m_PeopleList_First = NULL; 
    m_PeopleList_Last = NULL; 
} 
+0

Est-ce que le constructeur 'Person' définit' Next' à 'NULL'? Sinon, le dernier élément de votre liste liée va pointer vers des ordures. Je ne pense pas que cela causerait votre fuite de mémoire si. – Nate

+0

oui c'est le cas. Désolé pour cette ommision – kevin

Répondre

1

Ce n'est pas une indication d'une fuite de mémoire. Le système d'exploitation ne compte que les pages de 4 Ko assignées à votre processus. L'allocateur de tas qui s'exécute dans votre processus demandera et publiera des pages de système d'exploitation en votre nom. Le gestionnaire de tas peut conserver la mémoire après l'avoir relâchée, pour la réutiliser plus tard pour d'autres objets.

Vous devez instrumentaliser votre application pour détecter les fuites de mémoire et/ou effectuer des tests de tension de longue durée pour détecter les fuites accumulées.

+0

Merci pour votre contribution. Je pense que votre réponse du gestionnaire de tas en gardant la mémoire autour pour la réutilisation semble très possible. Je vais essayer de tester cela avec la réponse de Jerry. – kevin

2

Vous avez quelques problèmes ici. Tout d'abord, lorsque vous la mémoire delete, la bibliothèque standard normalement pas libérer cette mémoire à l'OS. Il conserve normalement la propriété de cette mémoire, mais la marque comme disponible pour d'autres allocations. Puisque vous utilisez apparemment MS VC++, vous pouvez utiliser _heapwalk après avoir fait delete s pour voir les blocs libres encore dans le tas du processus. Si vous voulez vraiment, vous pouvez également appeler _heapmin pour libérer (au moins la plus grande partie) de cette mémoire libre vers le système d'exploitation. Retour en arrière quand (MS VC++ 4.0, si la mémoire est utilisée) MS avait une version de la bibliothèque standard qui utilisait directement la gestion de la mémoire du système d'exploitation, mais les performances étaient lamentables (pour le dire gentiment).Deuxièmement, MFC a une quantité passable en arrière-plan où il alloue diverses «choses» pour faire fonctionner les choses, mais ne les libère pas immédiatement après (et comme la plupart d'entre elles est plus ou moins invisible, il n'y a pas de moyen facile/direct pour vous de le libérer non plus).

+0

Encore une fois merci pour votre contribution. Vous m'avez donné quelques éléments utiles à suivre dans mon enquête (_heapwalk et _heapMin). Je vais modifier mon programme et voir l'impact de _heapmin. En ce qui concerne votre deuxième commentaire avec le MFC, je suppose que je pourrais changer mon programme simple pour être une simple application console Win32 pour supprimer le MFC afin de réduire le nombre de variables dans cette équation. Merci. – kevin

+0

@kevin: Je ne voudrais pas retirer MFC juste jet. Les bibliothèques MFC disposent d'un suivi des fuites de mémoire intégré facultatif. Vous obtenez un journal à la sortie de l'application de tous les objets que vous avez échoué à supprimer. Très utile. http://msdn.microsoft.com/en-us/library/c99kz476(VS.80).aspx –

+0

@jdv: Tout à fait vrai. Bien que ce soit moins connu, vous pouvez obtenir des choses assez similaires sans MFC (http://msdn.microsoft.com/en-us/library/x98tx3cf(VS.80).aspx). –

Questions connexes