Comment convaincre le gestionnaire de mémoire pour libérer la mémoire inutilisée

StackOverflow https://stackoverflow.com/questions/4475592

  •  11-10-2019
  •  | 
  •  

Question

Dans un récent ( Mon programme ne libère la mémoire de retour. Pourquoi? ) Je montre que lors de l'utilisation FastMM, l'application ne libère pas de quantités importantes de mémoire au système. Récemment, j'ai créé un programme de test artificiel pour vous assurer que la question n'est pas une mémoire et qu'elle n'apparaît avec FastMM.

Dans ce programme, je crée et détruire un objet (identique à celui utilisé dans le post précédent) 500 fois.

Les besoins en mémoire sont ( "jeu de travail privé"):

Sans FastMM
Avant de lancer la boucle: 1.2MB
Après avoir exécuté la boucle: 2.1MB

Avec FastMM (mode de débogage agressif)
Avant de lancer la boucle: 2.1MB
Après avoir exécuté la boucle: 25MB

Avec FastMM (mode de libération)
Avant de lancer la boucle: 1.8MB
Après avoir exécuté la boucle: 3MB

Si je lance la boucle à plusieurs reprises, l'exigence de mémoire n'augmente pas. Ce qui signifie que la mémoire non libéré est réutilisée si ce n'est pas une fuite de mémoire (une fuite de mémoire augmenterait l'empreinte mémoire avec plusieurs KB / MB à chaque exécution).


Mes questions sont les suivantes:

Comment puis-je désactiver ce comportement dans FastMM? Est-il même possible? Je sais que, si je libère le programme sans FastMM ou avec FastMM Déclenc il « déchets » des quantités modérées de RAM. Mais la désactivation de ce comportement à la demande, va me aider (nous?) Identifier les fuites de mémoire. En fait, dans mon premier post (voir le lien) beaucoup de gens suggéré que j'ai une fuite. La confusion a été créée évidemment juste à cause de ce comportement. Non, il est évident qu'il n'y a pas de fuite. Il est juste le gestionnaire de mémoire qui refuse de libérer de grandes quantités de mémoire.

Il ne sera jamais libérer la mémoire supplémentaire? Quand? Qu'est ce qui déclenche cela? le programmeur peut déclencher? Par exemple, quand je sais que je l'ai terminé une tâche intensive RAM et l'utilisateur ne peut pas utiliser le programme pendant un certain temps (minimiser), puis-je vider le dos RAM au système? Qu'est-ce qui se passe quand l'utilisateur ouvre plusieurs instances de mon programme? Ils ne vont pas en compétition pour la RAM?

Était-ce utile?

La solution 4

RESOLU

Comme suggéré par Barry Kelly la mémoire sera automatiquement par FastaMM. Pour confirmer que ce que j'EMBALLÉES un deuxième programme qui a alloué beaucoup de RAM. Dès que Windows a manqué de RAM, mon utilisation de la mémoire du programme est revenu à sa valeur d'origine.

Problème résolu. Merci Barry.

Autres conseils

Vous ne devriez pas penser que « perdre » RAM, vraiment. Pensez-y comme « cache » RAM inutilisée. Le gestionnaire de mémoire tient sur la mémoire non utilisée au lieu de le libérer vers le système d'exploitation pour une raison, et en fait, vous avez frappé à cette raison dans votre question.

Vous avez dit que vous gardez réexécuter les mêmes opérations dans une boucle. Quand vous faites cela, il a encore la vieille mémoire disponible et il peut lui attribuer immédiatement, au lieu d'avoir à demander à Windows pour un nouveau morceau de tas. Ceci est l'une des tours qui met le « Fast » dans « FastMM, » et si elle n'a pas fait que vous trouveriez votre programme en cours d'exécution beaucoup plus lentement.

Vous n'avez pas à vous soucier de la figure de mode de débogage FastMM. C'est seulement pour le débogage, et vous n'allez pas publier un programme compilé avec FullDebugMode. Et la différence entre « sans FastMM » et « avec FastMM Release Mode » est d'environ 1 Mo, ce qui est négligeable sur le matériel moderne. Pour le faible coût de seulement 1 Mo supplémentaire, vous obtenez un gain important de performances. Donc, ne vous inquiétez pas à ce sujet.

Une partie de ce qui rend FastMM est rapide qu'il attribuera un grand bloc de mémoire et de se tailler plus petits morceaux de taille uniforme hors de lui. Si une partie du bloc est utilisé, rien ne peut être remis à l'OS.

Vous êtes invités à utiliser un gestionnaire de mémoire différent. Une approche serait d'acheminer toutes les allocations directement à VirtualAlloc . Les allocations seront arrondies à occuper une page entière à la fois, afin que votre programme peut souffrir si vous avez beaucoup de petites allocations, mais lorsque vous appelez VirtualFree, vous pouvez être sûr que la mémoire ne certainement pas appartiennent à votre programme plus.

Une autre option est d'acheminer tout le tas OS. Utilisez HeapAlloc . Vous pouvez même activer le tas à faible fragmentation pour votre programme (par par défaut à partir de Windows Vista), qui fera l'OS emploient une stratégie similaire à celle utilisée par FastMM, mais il vous permettra d'utiliser certains débogage et des outils d'analyse de Microsoft pour suivre l'utilisation au fil du temps de la mémoire de votre programme. Prenez garde, cependant, que vous appelez après HeapFree, certaines mesures pourraient encore montrer la mémoire comme appartenant à votre programme.

Par ailleurs, le jeu de travail fait référence à la mémoire de actuellement dans la RAM physique . Que vous avez observé le nombre monte ne veut pas dire que votre programme a alloué plus de mémoire. Il peut simplement signifier que votre programme touché de la mémoire qu'il avait déjà alloué, mais qui n'a pas encore été mis en RAM. Au cours de votre boucle, vous avez effleuré que la mémoire et le système d'exploitation n'a pas décidé de la page en arrière sur encore sur le disque.

J'utilise les éléments suivants en tant que gestionnaire de mémoire. Je le fais parce qu'il est bien meilleur en conflit de thread que FastMM qui est en fait assez pauvre. Je sais qu'un gestionnaire évolutif tel que Hoard serait mieux, mais cela est fonctionne très bien pour mes besoins.

unit msvcrtMM;

interface

implementation

type
  size_t = Cardinal;

const
  msvcrtDLL = 'msvcrt.dll';

function malloc(Size: size_t): Pointer; cdecl; external msvcrtDLL;
function realloc(P: Pointer; Size: size_t): Pointer; cdecl; external msvcrtDLL;
procedure free(P: Pointer); cdecl; external msvcrtDLL;

function GetMem(Size: Integer): Pointer;
begin
  Result := malloc(size);
end;

function FreeMem(P: Pointer): Integer;
begin
  free(P);
  Result := 0;
end;

function ReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  Result := realloc(P, Size);
end;

function AllocMem(Size: Cardinal): Pointer;
begin
  Result := GetMem(Size);
  if Assigned(Result) then begin
    FillChar(Result^, Size, 0);
  end;
end;

function RegisterUnregisterExpectedMemoryLeak(P: Pointer): Boolean;
begin
  Result := False;
end;

const
  MemoryManager: TMemoryManagerEx = (
    GetMem: GetMem;
    FreeMem: FreeMem;
    ReallocMem: ReallocMem;
    AllocMem: AllocMem;
    RegisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak;
    UnregisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak
  );

initialization
  SetMemoryManager(MemoryManager);

end.

Ce n'est pas une réponse à votre question, mais il est trop long pour entrer dans un commentaire et vous pouvez le trouver intéressant d'exécuter votre application contre ce MM. Je suppose qu'il effectuera la même manière que FastMM.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top