2010-10-05 3 views
1

j'ai un morceau de code C++ qui libère la mémoire comme suitMontant de l'augmentation de la mémoire physique que je libérer des blocs

for (int i = Pages-1; i >= NewPages; i--) 
{ 
    LPVOID p = m_Pages[i]; 
    free(p); 
} 

Alors que le code fonctionne bien, lorsqu'il est appelé à partir d'un gestionnaire d'exception, il fonctionne très lentement. En regardant le gestionnaire de tâches tout en faisant un pas à travers la boucle ci-dessus, la quantité de mémoire physique utilisée par le processus (Mem Usage) augmente avec chaque appel à libérer, tandis que la mémoire virtuelle (VM Size) reste la même. Finalement, le processus se termine anormalement.

Le code qui alloue la mémoire qui lève l'exception est le suivant;

for (int i = Pages; i < NewPages; i++) 
{ 
    LPVOID p = malloc(m_ElementsPerPage*m_ElementSize); 
    if (!p) 
     AfxThrowMemoryException(); 
    m_Pages.Add(p); 
} 

maintenant un coup d'oeil, je crois que si j'inverse l'ordre de la boucle de désaffectation, de telle sorte que le dernier bloc alloué est le premier libéré, je pourrais éviter ce problème. Mais existe-t-il une raison pour laquelle l'utilisation de la mémoire de processus devrait augmenter avec un appel à libérer, et pourquoi l'appel libre sur un bloc de mémoire de tas valide devrait provoquer la fin du programme? (n.b. la terminaison pourrait bien être liée au débogueur plutôt qu'à l'application elle-même).

Edit: Le système d'exploitation est Windows XP SP3, le compilateur est MSVC++ 8

Edit2: Une version plus complète du code est la suivante;

void MyArray::ResizeArray(int NewPages) 
{ 
    int Pages = m_Pages.GetSize(); 
    if (NewPages != Pages) 
    { 
     if (NewPages > Pages) // Grow the page array 
     { 
      for (int i = Pages; i < NewPages; i++) 
      { 
       LPVOID p = malloc(m_ElementsPerPage*m_ElementSize); 
       if (!p) 
        AfxThrowMemoryException(); 
       m_Pages.Add(p); 
      } 
     } else // Shrink the page array 
     { 
      for (int i = Pages-1; i >= NewPages; i--) 
      { 
       LPVOID p = m_Pages[i]; 
        free(p); 
      } 
      m_Pages.SetSize(NewPages); 
     } 
    } 
} 
+0

Le tas est corrompu. Mettez à jour votre système d'exploitation, vous obtiendrez un diagnostic précoce au lieu de simplement labourer dans l'abîme. –

+0

semble que le problème existe ailleurs. – wheaties

+3

Il me semble que la mémoire allouée a été échangée sur le disque, et l'appel à libérer ramène réellement les pages de mémoire en RAM, ce qui pourrait expliquer la lenteur et l'utilisation de la mémoire physique accrue. – SirDarius

Répondre

1

Votre processus peut utiliser deux mégaoctets de mémoire. Lorsque malloc échoue, la mémoire utilisée sera proche de cette valeur. Si votre ordinateur a moins de mémoire physique, beaucoup de pages de mémoire de ce processus auront été paginées sur le disque. Pendant que votre gestionnaire d'exceptions libère de la mémoire, le gestionnaire de tas touche toutes les pages et les ramène à la mémoire physique. Ce sera lent.

C'est ce que vous observez avec le Gestionnaire des tâches.Les noms de colonne sont trompeurs: VM Size est en réalité de la mémoire privée, qui ne changera pas car la mémoire libérée n'est pas restituée au système par le gestionnaire de tas (en répondant à la question pourquoi serait une question en soi). L'utilisation de Mem est la taille de l'ensemble de travail du processus, c'est-à-dire la mémoire physique utilisée par ce processus. Il augmentera à mesure que les pages sont mappées vers la mémoire physique à partir du fichier de page. Vous ne mentionnez pas comment le processus se termine anormalement, mais une fragmentation peut également se produire dans la mémoire, ce qui peut expliquer que les mallocs puissent continuer à échouer même après avoir libéré votre matrice.

3

Votre compte en boucle d'allocation de Pages jusqu'à NewPages tandis que le nombre de vos boucles de désallocation de Pages-1 vers le bas à NewPages. Un seul peut être correct, en fonction de Pages <= NewPages ou non. Si la boucle de désallocation est celle qui ne va pas, alors vous essayez de libérer des "pointeurs" qui ne sont que des valeurs de mémoire aléatoires, pouvant causer n'importe quoi, comme une terminaison anormale de votre programme. Mis à part cela, appeler le free() ne diminuera pas nécessairement la taille de la mémoire de votre programme. Cela dépend de l'implémentation de malloc()/free() comment exactement cette mémoire est gérée en interne. malloc gérera la mémoire en interne d'une manière ou d'une autre et ne rendra pas nécessairement immédiatement tout ce qui est libéré sur le système d'exploitation. Il est probablement simplement marqué en interne comme "libre" et le réutiliserait lors d'appels ultérieurs au malloc(). En outre, s'il y a d'autres blocs de mémoire encore alloués sur la même page de mémoire, ne peut pas redonner la page au système d'exploitation pour le moment.

La mémoire physique utilisée peut augmenter car la mémoire libérée doit être permutée, si votre implémentation malloc stocke des informations de gestion à côté du bloc alloué (par exemple, la taille du bloc). Free aura besoin de lire/modifier ces informations de gestion pour faire son travail, et pour cela la mémoire doit d'abord être permutée.

+0

Un peu d'explication sur les variables, Pages est le nombre actuel de pages dans le tableau, NewPages est le nombre de pages demandé, qui peut être plus petit pour appeler le premier morceau de code pour diminuer le tableau sixe, ou plus pour appeler le deuxième morceau de code pour augmenter la taille du tableau. J'ai édité la question pour mieux refléter ce qui se passe ici. –

Questions connexes