9
votes

Fragmentation de tas et gestionnaire de mémoire Windows

J'ai des problèmes avec la fragmentation de la mémoire dans mon programme et ne pas pouvoir attribuer des blocs de mémoire très volumineux après un moment. J'ai lu les postes liés sur ce forum - principalement Ceci un. Et j'ai encore des questions.

J'utilise un espace mémoire profileur pour obtenir une photo de la mémoire. J'ai écrit un programme de 1 ligne contenant CIN >> Var; et a pris une photo de la mémoire:

Texte alt http://img22.imageshack.us/img22/6808/Memoryk .gif Où sur le dessus Arc - Vert indique l'espace vide, jaune alloué, rouge commité. Ma question est la suivante: la mémoire allouée à droite? Est-ce la pile pour le fil principal? Cette mémoire ne va pas être libérée et divise la mémoire continue dont j'ai besoin. Dans ce programme simple 1 ligne, la scission n'est pas aussi mauvaise. Mon programme actuel a davantage de choses allouées au milieu de l'espace d'adresses et je ne sais pas où il vient de. Je n'allocie pas encore cette mémoire.

  1. Comment puis-je essayer de résoudre ceci? Je pensais à passer à quelque chose comme Nedmalloc ou Dlmalloc. Cependant, cela ne s'appliquerait aux objets que j'alloque explicitement moi-même, tandis que la scission indiquée dans l'image ne partirait pas? Ou existe-t-il un moyen de remplacer l'allocation CRT avec un autre gestionnaire de mémoire?

  2. Parler d'objets, y a-t-il des emballages pour Nedmalloc pour C ++ afin que je puisse utiliser de nouvelles et supprimez pour allouer des objets?

    Merci.


1 commentaires

Microsoft Security Essentials pense que l'application "Profiler" liée à la question initiale contient le win32.bisar! Trojan RTS.


5 Réponses :


1
votes

pourrait-il être l'exécutable? Il doit être chargé dans l'espace d'adresses quelque part ....

Quant à 2 c'est assez facile à remplacer les nouvelles fonctions mondiales et supprimées ... Définissez-les simplement.


0 commentaires

2
votes

Je suppose que vous allez fréquemment allouer et traiter des objets de tailles variables et que c'est ce qui conduit à vos problèmes de fragmentation de la mémoire?

Il existe différentes stratégies de travailler autour de ceux-ci; Les différents gestionnaires de mémoire que vous avez mentionnés peuvent aider s'ils peuvent résoudre le problème de la fragmentation pour vous, mais cela nécessiterait un peu plus d'analyse des causes sous-jacentes de la fragmentation. Par exemple, si vous allouez fréquemment des objets de trois ou quatre types et que ceux-ci ont tendance à aggraver le problème de la fragmentation de la mémoire, vous voudrez peut-être mettre ceux-ci dans leurs propres pools de mémoire pour permettre la réutilisation des blocs de mémoire de la taille correcte. De cette façon, vous devez disposer d'un ensemble de blocs de mémoire disponibles qui correspondent à cet objet particulier et empêchent le scénario commun que l'attribution de l'objet X diviser un bloc de mémoire suffisamment grand pour contenir Y de telle manière que vous ne pouvez pas allouer. plus.

quant à (2), je ne suis pas au courant d'une enveloppe autour de Nedmalloc (franchement, je ne suis pas très familier avec Nedmalloc), mais vous pouvez créer vos propres emballages très facilement, car vous pouvez soit créer des opérateurs spécifiques à une classe neufs et supprimer ou même surcharger / remplacer les opérateurs globaux nouveaux et supprimer. Je ne suis pas un grand fan de ces derniers, mais si votre allocation "hotspot" consiste en une poignée de cours, il est généralement assez facile de les moderniser avec leurs propres opérateurs spécifiques à une classe neuf et supprimer.

Cela dit, NedMallOCOC se facture comme un remplacement de la standard MALLOC / GRATUIT et du moins avec les compilateurs MS, je pense que la bibliothèque d'exécution C ++ sera transmise neuf / Supprimera à MALLOC / GRATUITE, il pourrait donc bien être un cas de Construire votre exécutable avec Nedmalloc.


0 commentaires

1
votes

Le meilleur moyen de savoir où la mémoire est allouée dans votre programme consiste à utiliser un débogueur. Il y a des allocations pour chaque DLL chargé et l'exécutable lui-même, et tous fragmentez la mémoire virtuelle. De plus, l'utilisation de bibliothèques C / C ++ et de Windows API provoquera la création d'un tas dans votre application, qui réservera tout le moins une partie de la mémoire virtuelle.

Vous pouvez par exemple utiliser virtualalloc pour réserver un grand chunck de mémoire virtuelle. Dans un programme relativement petit, seulement pour constater que le Virtualalloc échoue, soit l'application échoue plus tard lorsqu'il tente de charger une nouvelle DLL (etc.), vous ne pouvez pas toujours contrôler les dlls chargés et où. De nombreux produits A / V et d'autres produits injecteront des DLL dans tous les processus en cours d'exécution. Lorsque cela se produit, ces DLL ont souvent un premier choix à des adresses de charge - c'est-à-dire que leur compilation / liée de défaut sera probablement accordée. Sur l'espace d'adressage virtuel de 2 Go disponible d'une application Windows typique de 32 bits, si une DLL se charge au milieu de cet espace d'adressage, la plus grande allocation / réservation que vous pouvez acquérir sera inférieure à 1 Go. P> Si vous utilisez WINDBG, vous pouvez voir quelles régions de mémoire sont consommées, réservées, etc. La commande LM vous montrera les adresses de charge de toutes les DLL et de l'EXE et de leur gamme. La commande! Vadump vous montrera toute la mémoire virtuelle utilisée par le processus et les protections de la page. Les protections de la page sont une grosse indice dans ce qui existe. Par exemple, dans ce qui suit (partiel)! Vadump d'un processus Calc.exe 64 bits, vous verrez que la première région est simplement une plage de mémoire virtuelle protégée de l'accès. (Entre autres choses, cela vous empêche d'attribuer la mémoire à l'adresse 0.) MEM_COMMIT signifie que la mémoire est soutenue par la RAM ou le fichier de pagination. Page_Readwrite est peut-être une mémoire en tas, ou le segment de données d'un module chargé. Page_readexecute est généralement du code chargé et qui apparaîtra dans la liste produite par LM. Mem_Reserve signifie que quelque chose a appelé Virtualalloc pour réserver une région de mémoire, mais qu'il n'est pas mappé par le gestionnaire de mémoire virtuel, etc. P>

0:004> !vadump
BaseAddress:       0000000000000000
RegionSize:        0000000000010000
State:             00010000  MEM_FREE
Protect:           00000001  PAGE_NOACCESS

BaseAddress:       0000000000010000
RegionSize:        0000000000010000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00040000  MEM_MAPPED

BaseAddress:       0000000000020000
RegionSize:        0000000000003000
State:             00001000  MEM_COMMIT
Protect:           00000002  PAGE_READONLY
Type:              00040000  MEM_MAPPED


0 commentaires

12
votes

Premier, merci d'avoir utilisé mon outil. J'espère que vous le trouverez utile et n'hésitez pas à soumettre des demandes de fonctionnalité ou des contributions.

Typiquement, des tranches minces à des points fixes dans l'espace d'adressage sont causées par des DLL liées de chargement à leur adresse préférée. Ceux qui chargent hautement dans l'espace d'adressage ont tendance à être des DLL de système d'exploitation Microsoft. Il est plus efficace pour le système d'exploitation si ceux-ci peuvent tous être chargés à leurs adresses préférées, car les parties en lecture seule des DLL peuvent tous être partagées entre les processus.

La tranche que vous pouvez voir n'est rien à craindre, il ne cesse rien de votre espace d'adressage. Comme vous l'avez noté, il existe des DLL, cependant, qui se chargeent à d'autres points de l'espace d'adresses. IIRC shlwapi.dll est un exemple particulièrement mauvais, chargement à environ 0x2000000 (à nouveau IIRC) qui divise souvent une grande partie de l'espace d'adressage disponible en deux pièces plus petites. Le problème avec ceci est qu'une fois la DLL chargée, vous ne pouvez rien faire pour déplacer cet espace allouer.

Si vous liez la DLL (directement ou via une autre DLL), vous ne pouvez rien faire. Si vous utilisez LoadLibrary , vous pouvez obtenir sournois et réserver son adresse préférée, le forçant à être déplacé - souvent mieux dans l'espace d'adresses - avant de libérer la mémoire réservée. Cela ne fonctionne pas toujours, cependant.

sous la hotte, l'adresse de l'espace moniteur utilise virtualqueryex pour examiner l'espace d'adressage du processus, mais il existe un autre appel de la bibliothèque PSAPI que d'autres outils utilisent (par exemple, Explorateur de processus ) qui peut vous montrer quels fichiers (y compris les DLL) sont mappés dans lesquels des parties de l'espace d'adresses.

Comme vous l'avez trouvé, cela peut être manifeste facile à manquer de pièce dans un espace d'adresses utilisateur de 2 Go. Fondamentalement, vous êtes la meilleure défense contre la fragmentation de la mémoire, il suffit de ne pas nécessiter de gros blocs de mémoire contigus. Bien que difficile à rétro-ajustement, la conception de votre application à travailler avec des morceaux de «taille moyenne» constitue généralement une utilisation sensiblement plus efficace de l'espace d'adresses.

De même, vous pouvez utiliser une stratégie de pagination, éventuellement à l'aide de fichiers mapé de mémoire ou Extensions de fenêtres d'adresse .


3 commentaires

Hé et merci pour un excellent outil et pointant cette caractéristique de l'explorateur de processus.


@CHARLES BAILEY: Reliaison statique - ne pouvait-il pas être rebasé une DLL?


Oui, vous pouvez retrouver des dlls, et cette peut aider à optimiser la fragmentation d'espace d'adresses et les heures de chargement, cependant ... Typiquement, vous ne devriez généralement le faire avec des DLL que vous possédez et si vous faites trop de micro-ormisations. Vous vous retrouvez avec un ensemble de DLL qui fonctionnent bien dans un exe particulier à un moment donné, mais pour tout autre exe n'a pas une bonne stratégie de chargement optimisée. Si vos dlls ont ré-construit et modifier la taille, vous devez passer à nouveau le processus. Cela peut donc fonctionner, dans une certaine mesure, mais si vous devez y recourir, vous pouvez vous retrouver dans un cercle vicieux de maintenance.



2
votes

Afin de réduire la fragmentation de la mémoire, vous pouvez profiter du Windows Bas-fragmentation Heap . Nous avons utilisé cela dans notre produit à un bon effet et n'a pas eu presque autant de problèmes de mémoire que depuis.


1 commentaires

J'ai vu cette fonctionnalité. Cependant, afin de le permettre, vous devez exécuter des informations sur le tas (). L'instantané de la mémoire a été prélevé à la première ligne de la principale () et déjà la mémoire est fragmentée après la première 1,3 Go d'espace d'adresses. Après avoir regardé l'explorateur de processus, il s'agit de DLL et d'autres choses. Ainsi, LFH peut aider mais cela n'empêche pas la fragmentation qui se produit déjà à cause de la chargement de la DLL.