Qu'est-ce que la fragmentation de la mémoire?
J'ai entendu le terme "fragmentation de la mémoire" utilisé à quelques reprises dans le cadre de C++ allocation dynamique de la mémoire. J'ai trouvé quelques questions sur la façon de traiter avec la fragmentation de la mémoire, mais ne peut pas trouver une question directe qui traite avec lui. Donc:
- Qu'est-ce que la fragmentation de la mémoire?
- Comment puis-je savoir si une fragmentation de la mémoire est un problème pour mon application? Ce genre de programme est susceptible de souffrir le plus?
- Que sont le bien commun des moyens pour traiter la fragmentation de la mémoire?
Aussi:
- J'ai entendu à l'aide des allocations dynamiques, beaucoup de choses peuvent augmenter la fragmentation de la mémoire. Est-ce vrai? Dans le contexte de C++, je comprends tous les conteneurs standard (std::string, std::vector, etc) utiliser l'allocation dynamique de la mémoire. Si ceux-ci sont utilisés tout au long d'un programme (std::string), est la fragmentation de la mémoire plus de chances d'être un problème?
- Comment peut-fragmentation de la mémoire soit traitée avec STL-lourds de l'application?
- Beaucoup de réponses, merci à tous!
- Il y a déjà beaucoup de bonnes réponses, mais voici quelques photos d'un réel de l'application (Firefox), où la fragmentation de la mémoire a été un gros problème: blog.pavlov.net/2007/11/10/memory-fragmentation
- le lien ne marche plus, c'est pourquoi il est important de fournir un bref résumé ainsi que le lien ou de répondre à la question avec un résumé avec le lien
- Certes, mais c'est plus de la moitié d'une décennie
- Ci-dessous est une mise à jour de l'emplacement pour les liens posté par Marius:pavlovdotnet.wordpress.com/2007/11/10/memory-fragmentation
- Un très intéressant exemple dans la réalité du problème (Élémentaire de la Guerre de la Magie): youtu.être/_zD33Hrbo4Y
Vous devez vous connecter pour publier un commentaire.
Imaginez que vous avez un "gros" (32 octets) étendue de libérer de la mémoire:
Maintenant, allouer une partie de celui-ci (5 affectations):
Maintenant, gratuit les quatre premières affectations, mais pas le cinquième:
Maintenant, essayez d'allouer à 16 octets. Oups, je ne peux pas, même si il n'y a presque le double de celui de beaucoup gratuit.
Sur les systèmes avec de la mémoire virtuelle, la fragmentation est moins un problème que vous pourriez penser, parce que les grandes affectations doivent être contigus dans virtuel de l'espace d'adresse, pas dans physique espace d'adressage. Donc, dans mon exemple, si j'avais de la mémoire virtuelle avec une taille de page de 2 octets puis j'ai pu faire mon 16 allocation d'octets sans problème. La mémoire physique ressemblerait à ceci:
alors que la mémoire virtuelle (beaucoup plus grand) pourrait ressembler à ceci:
Le symptôme classique de fragmentation de la mémoire, c'est que vous essayez d'affecter un gros bloc et vous ne pouvez pas, même si vous semblez avoir assez de mémoire libre. Une autre conséquence est l'impossibilité pour le processus de libération de la mémoire pour le système d'exploitation (parce qu'il y a un objet, encore en usage dans tous les blocs, il a alloué à partir de l'OS, même si ces blocs sont maintenant la plupart du temps non utilisé).
Tactiques pour empêcher la fragmentation de la mémoire en C++ de travail par l'affectation d'objets de différentes zones en fonction de leur taille et/ou leur durée de vie prévue. Donc, si vous allez créer un grand nombre d'objets et de détruire tous ensemble, plus tard, de les allouer de la mémoire de la piscine. Les autres allocations de vous faire entre eux ne sera pas de la piscine, donc de ne pas être situé entre dans la mémoire, afin que la mémoire ne sera pas fragmenté en conséquence.
En général, vous n'avez pas besoin de s'inquiéter beaucoup, à moins que votre programme est longue et fait beaucoup de répartition et de la libération. C'est quand vous avez des mélanges de courte durée et longue durée de vie des objets que vous êtes plus à risque, mais même alors,
malloc
fera de son mieux pour vous aider. Fondamentalement, l'ignorer jusqu'à ce que votre programme a des échecs d'allocation ou de façon inattendue, le système de manquer de mémoire (attraper ce, dans l'essai, de préférence!!!).Les bibliothèques standard sont pas pire que n'importe quoi d'autre qui alloue de la mémoire, et des conteneurs standard ont tous un
Alloc
paramètre de modèle que vous pourriez utiliser pour affiner leur stratégie de répartition si cela est absolument nécessaire.Fragmentation de la mémoire, c'est quand la plupart de votre mémoire est allouée dans un grand nombre de non-blocs contigus, ou en morceaux, laissant un bon pourcentage du montant total de votre mémoire non alloué, mais inutilisable pour la plupart des scénarios typiques. Il en résulte de la mémoire des exceptions, ou des erreurs d'allocation (c'est à dire malloc renvoie la valeur null).
La façon la plus simple de penser à ce sujet est d'imaginer que vous avez un grand mur vide que vous avez besoin de mettre des photos de différentes tailles sur. Chaque image prend une certaine taille et évidemment on ne peut pas le découper en petits morceaux pour les faire rentrer. Vous avez besoin d'un endroit vide sur le mur, la taille de l'image, ou autre chose que vous ne pouvez pas le mettre en place. Maintenant, si vous commencez à accrocher des images sur le mur et vous n'êtes pas prudent sur la façon dont vous organiser, vous allez bientôt vous retrouver avec un mur partiellement couvert avec des photos et même si vous avez des spots vide, la plupart des nouveaux photos ne conviennent pas, car ils sont plus grands que les places disponibles. Vous pouvez toujours accrocher vraiment des petites images, mais la plupart de ceux qui ne fit. De sorte que vous aurez à ré-arranger (compact) celles qui sont déjà sur le mur pour faire de la place..
Maintenant, imaginez que le mur est votre (tas) de la mémoire et les images sont des objets.. C'est la fragmentation de la mémoire..
Comment puis-je savoir si une fragmentation de la mémoire est un problème pour mon application? Ce genre de programme est susceptible de souffrir le plus?
Un signe révélateur que vous avez peut-être affaire à une fragmentation de la mémoire est si vous avez de nombreuses erreurs d'allocation, en particulier lorsque le pourcentage de mémoire utilisée est élevée mais non vous n'avez pas encore utilisé la totalité de la mémoire - donc, techniquement, vous devriez avoir beaucoup de place pour les objets que vous essayez d'allouer.
Lorsque la mémoire est très fragmenté, les allocations de mémoire sera probablement prendre plus de temps parce que l'allocateur de mémoire a faire plus de travail pour trouver un espace approprié pour le nouvel objet. Si, à son tour, vous avez de nombreuses allocations de mémoire (dont vous n'avez probablement depuis que vous vous retrouviez avec une fragmentation de la mémoire) à l'attribution de temps et peut même provoquer des délais d'attente.
Que sont le bien commun des moyens pour traiter la fragmentation de la mémoire?
D'utiliser un algorithme d'allocation de mémoire. Au lieu d'allouer de la mémoire pour un grand nombre de petits objets, de pré-allouer de la mémoire pour un tableau contigu de ces objets de petite taille. Parfois un peu de gaspillage lors de l'allocation de la mémoire peut aller un long chemin pour la performance et peut vous épargner la peine d'avoir à traiter avec une fragmentation de la mémoire.
Fragmentation de la mémoire est le même concept que la fragmentation du disque: il se réfère à l'espace gaspillé parce que les zones en cours d'utilisation ne sont pas emballés assez étroitement ensemble.
Supposons que, pour un jouet simple exemple que vous avez dix octets de mémoire:
Maintenant, nous allons allouer à trois blocs d'octets, nom de A, B, et C:
Maintenant libérer le bloc B:
Maintenant ce qui se passe si nous essayons d'allouer de quatre octets du bloc D? Eh bien, nous avons quatre octets de mémoire libre, mais nous n'avons pas quatre contiguë octets de mémoire libre, donc on ne peut pas allouer D! C'est l'utilisation inefficace de la mémoire, car nous aurions été en mesure de magasin de D, mais nous n'avons pas pu. Et on ne peut pas avancer C pour faire de la place, parce que très probablement certaines variables dans notre programme sont dirigés l'un vers C, et nous ne pouvons pas automatiquement rechercher et de modifier l'ensemble de ces valeurs.
Comment savez-vous que c'est un problème? Eh bien, le plus grand signe, c'est que votre programme de la taille de la mémoire virtuelle est beaucoup plus grande que la quantité de mémoire que vous utilisez réellement. Dans un exemple réel, vous auriez beaucoup plus de dix octets de la mémoire, afin D obtenir juste attribuées à compter d'un octet 9, et d'octets 3-5 resterait inutilisé, sauf si vous plus tard alloués quelque chose de trois octets de long ou plus petit.
Dans cet exemple, 3 octets n'est pas un tas de déchets, mais un cas pathologique où deux allocations de quelques octets sont, par exemple, une dizaine de mégaoctets à part dans la mémoire, et vous avez besoin d'allouer un bloc de la taille de 10 mo + 1 octet. Vous devez aller demander au système d'exploitation pour plus de dix mégaoctets plus de mémoire virtuelle pour le faire, même si vous êtes juste un octet timide d'avoir assez d'espace déjà.
Comment peut-on la prévenir? Le pire des cas, ont tendance à survenir lorsque vous fréquemment de créer et de détruire des petits objets, depuis que tend à produire un "fromage suisse" de l'effet avec de nombreux petits objets séparés par de nombreux petits trous, ce qui rend impossible d'allouer de plus gros objets dans les trous. Quand vous savez que vous allez être en faisant cela, une stratégie efficace consiste à pré-allouer un bloc de mémoire que d'une piscine pour vos petits objets, et de gérer manuellement la création de petits objets à l'intérieur de ce bloc, plutôt que de laisser la valeur par défaut de l'allocateur de la gérer.
En général, moins les allocations de vous, moins la mémoire est d'être fragmenté. Cependant, STL traite de cette façon relativement efficace. Si vous avez une chaîne qui est à l'aide de la totalité de son allocation actuelle et de vous ajouter un caractère, il ne se contente pas de ré-allouer à sa longueur actuelle plus un, il double sa longueur. C'est une variation sur le "pool de fréquentes petites allocations" de la stratégie. La chaîne est de saisir une grande partie de la mémoire afin qu'il puisse traiter efficacement avec la répétition de légères augmentations de la taille sans faire répétées de petites réaffectations. Tous les conteneurs STL, en fait, faire ce genre de chose, donc, en général, vous n'aurez pas besoin de trop s'inquiéter de la fragmentation causée par automatiquement-la réaffectation des conteneurs STL.
Même si bien sûr des conteneurs STL n'avez pas de mémoire en pool entre les uns des autres, donc si vous prévoyez de créer de nombreux petits conteneurs (plutôt que quelques conteneurs qui sont redimensionnés souvent), vous pourriez avoir à vous préoccuper de la prévention de la fragmentation de la même manière que vous le feriez pour n'importe quel fréquemment créé de petits objets, STL ou pas.
Fragmentation de la mémoire est le problème de la mémoire devient inutilisable, même si elle est théoriquement disponible. Il existe deux types de fragmentation: la fragmentation interne est la mémoire qui est allouée, mais ne peut pas être utilisée (par exemple, lorsque la mémoire est allouée dans 8 octets morceaux mais le programme à plusieurs reprises n'unique allications quand elle a besoin de seulement 4 octets). la fragmentation externe est le problème de la mémoire libre de devenir divisée en de nombreux petits morceaux de sorte que les grandes demandes d'allocation ne peut pas être respecté, même si il est assez globale de la mémoire libre.
fragmentation de la mémoire est un problème si votre programme utilise beaucoup plus de mémoire vive que son réel paylod données exigerait (et vous avez exclu des fuites de mémoire).
Utiliser un bon programme d'allocation de mémoire. IIRC, ceux qui utilisent un meilleur ajustement de la stratégie sont généralement bien supérieure à éviter la fragmentation, si un peu plus lent. Cependant, il a également été montré que, pour toute stratégie de répartition, il y a pire des cas pathologiques. Heureusement, les schémas de répartition de la plupart des applications sont en fait relativement bénigne pour les allocateurs à manipuler. Il y a un tas de papiers là-bas si vous êtes intéressé par les détails:
Atelier International sur la Gestion de la Mémoire, Springer Verlag LNCS, 1995
Dans les ACM SIG-PLAN d'Avis, volume 34, No 3, pages 26 à 36, 1999
Mise à jour:
Google TCMalloc: Fil de mise en Cache de Malloc
Il a été constaté que il est assez bon au traitement de la fragmentation dans un long processus en cours d'exécution.
J'ai été le développement d'une application serveur qui présentaient des problèmes de fragmentation de mémoire sur HP-UX 11.23/11.31 ia64.
Ça ressemblait à ça. Il y a un processus qui fait les allocations de mémoire et deallocations et a couru pendant des jours. Et même s'il n'y avait pas de fuites de mémoire de la consommation de mémoire du processus a continué d'augmenter.
Au sujet de mon expérience. Sur HP-UX, il est très facile de trouver une fragmentation de la mémoire à l'aide de HP-UX gdb. Vous définissez un point de rupture et lorsque vous le frappez, vous exécutez cette commande:
info heap
et de voir toutes les allocations de mémoire pour le processus et la taille totale de mémoire. Ensuite, votre continuer votre programme et puis quelques temps plus tard, votre nouveau touché le point de rupture. Vous ne à nouveauinfo heap
. Si la taille totale de mémoire est plus grand, mais le nombre et la taille des allocations séparés sont le même, alors il est probable que vous avez des problèmes d'allocation mémoire. Si nécessaire, de faire cette case à quelques fore fois.Ma façon d'améliorer la situation était présent. Après j'avais fait une analyse avec HP-UX gdb, j'ai vu que des problèmes de mémoire ont été causés par le fait que j'ai utilisé
std::vector
pour le stockage de certains types d'informations à partir d'une base de données.std::vector
exige que ses données doivent être conservées dans un seul bloc. J'ai eu un peu de conteneurs, en se fondant surstd::vector
. Ces conteneurs ont été régulièrement recréé. Il y avait souvent des cas où de nouveaux records ont été ajoutés à la base de données et après que les récipients ont été recréés. Et depuis le recréé les conteneurs ont été plus elles ne rentrent pas dans des blocs de mémoire libre et de l'exécution demandé un nouveau grand bloc de l'OS. Comme un résultat, même s'il n'y avait pas de fuites de mémoire de la consommation de mémoire du processus a grandi. J'ai amélioré la situation quand j'ai changé les conteneurs. Au lieu destd::vector
j'ai commencé à utiliserstd::deque
qui a une manière différente de l'allocation de mémoire pour les données.Je sais que l'un des moyens d'éviter la fragmentation de la mémoire sur HP-UX est d'utiliser des Petits Bloc de l'Allocation ou de l'utilisation MallocNextGen. Sur RedHat Linux par défaut de l'allocateur semble gérer assez bien l'allocation d'une multitude de petits blocs. Sur Windows il y a
Low-fragmentation Heap
et il répond au problème d'un grand nombre de petites allocations.Ma compréhension est que dans un STL-lourds de l'application, vous devez d'abord identifier les problèmes. Allocateurs de mémoire (comme dans la libc) traitent le problème de beaucoup de petites allocations, ce qui est typique pour
std::string
(par exemple, dans mon application serveur, il y a beaucoup de chaînes de caractères STL mais comme je le vois à partir de l'exécutioninfo heap
ils ne sont pas la cause de tous les problèmes). Mon impression est que vous devez éviter de fréquentes et importantes allocations. Malheureusement, il ya des situations où vous ne pouvez pas l'éviter et modifier votre code. Comme je le dis dans mon cas, j'ai amélioré la situation lors de la mise àstd::deque
. Si vous identifiez votre mémoire fragmention il pourrait être possible d'en parler plus précisément.Fragmentation de la mémoire est le plus susceptible de se produire lorsque vous affecter et désallouer de nombreux objets de différentes tailles. Supposons que vous ayez la disposition suivante dans la mémoire:
Maintenant, quand
obj2
est sorti, vous avez 120 ko de mémoire inutilisée, mais vous ne pouvez pas allouer un bloc complet de 120 ko, parce que la mémoire est fragmentée.Techniques courantes à éviter cet effet comprennent anneau de tampons et objet piscines. Dans le contexte de la STL, des méthodes comme
std::vector::reserve()
peut vous aider.Une réponse très détaillée sur la fragmentation de la mémoire peut être trouvé ici.
http://library.softwareverify.com/memory-fragmentation-your-worst-nightmare/
C'est l'aboutissement de plus de 11 ans de fragmentation de la mémoire de réponses, j'offre aux gens de me poser des questions au sujet de la fragmentation de la mémoire à softwareverify.com
Lorsque votre application utilise la mémoire dynamique, il alloue et libère des morceaux de mémoire. Au début, l'ensemble de l'espace mémoire de votre application est un bloc contigu de mémoire libre. Toutefois, lorsque vous allouer et libérer des blocs de taille différente, la mémoire commence à se fragmenté, c'est à dire au lieu d'un grand contiguë bloc libre et un certain nombre de contiguë blocs alloués, il sera alloué et des blocs libres mélangés. Depuis les blocs libres ont une taille limitée, il est difficile de les réutiliser. E. g. vous pouvez avoir 1000 octets de mémoire libre, mais ne peut pas allouer de la mémoire pour un 100 octets du bloc, parce que tous les blocs libres sont à plus de 50 octets de long.
Un autre, inévitable, mais moins problématique source de fragmentation est que dans la plupart des architectures, des adresses de mémoire doit être aligné, 2, 4, 8, etc. les limites d'octets (c'est à dire les adresses doivent être des multiples de 2, 4, 8, etc.) Cela signifie que même si vous avez par exemple une structure contenant 3
char
champs, vos struct peuvent avoir une taille de 12 au lieu de 3, en raison du fait que chaque champ est aligné à une limite de 4 octets.La réponse la plus évidente est que vous obtenez un souvenir d'exception.
Apparemment, il n'est pas bon portable de façon à détecter une fragmentation de la mémoire en C++ apps. Voir cette réponse pour plus de détails.
Il est difficile en C++, car vous utilisez directement les adresses mémoire de pointeurs, et vous n'avez aucun contrôle sur qui fait référence à une mémoire spécifique de l'adresse. Afin de réorganiser la mémoire allouée blocs de la façon dont le garbage collector Java ne) n'est pas une option.
Un allocateur personnalisé peut aider par la gestion de l'allocation de petits objets dans une plus grande partie de la mémoire, et la réutilisation des logements libres à l'intérieur de ce morceau.
C'est un super-version simplifiée pour les nuls.
Comme des objets créés dans la mémoire, ils sont ajoutés à la fin de la portion utilisée dans la mémoire.
Si un objet qui n'est pas à la fin de la partie utilisée de la mémoire est supprimé, ce qui signifie que cet objet a été entre les 2 autres objets, il va créer un "trou".
C'est ce qu'on appelle la fragmentation.
Quand vous voulez pour ajouter un élément sur le tas ce qui se passe, c'est que l'ordinateur a à faire une recherche d'espace pour répondre à cet élément. C'est pourquoi les allocations dynamiques lorsqu'il n'est pas fait sur un pool de mémoire ou avec une mise en commun allocation "lent" des choses. Pour un gros STL demande si vous êtes en train de faire du multi-threading, il est le Hoard allocateur ou la Intel TBB version.
Maintenant, lorsque la mémoire est fragmentée, deux choses peuvent se produire:
De fragmentation de mémoire se produit parce que les blocs de mémoire de tailles différentes sont demandées. Considérons un tampon de 100 octets. Vous demandez à deux caractères, puis un entier. Maintenant, vous gratuit les deux caractères, puis demander un nouveau entier - mais cet entier ne peut pas tenir en l'espace de deux caractères. Que la mémoire ne peut pas être ré-utilisé car il n'est pas dans un assez grand bloc contigu de ré-allouer. En plus de cela, vous avez invoqué un lot de l'allocation de frais généraux pour vos chars.
Essentiellement, la mémoire vient seulement dans des blocs d'une certaine taille sur la plupart des systèmes. Une fois que vous divisez ces blocs, ils ne peuvent pas être rejoint jusqu'à ce que l'ensemble du bloc est libéré. Cela peut conduire à des blocs entiers en cours d'utilisation alors qu'en réalité, seule une petite partie du bloc est en cours d'utilisation.
Le principal moyen de réduire la fragmentation du segment est de faire de grands, de moins en moins fréquentes allocations. Dans les cas extrêmes, vous pouvez utiliser un tas managé qui est capable de déplacer des objets, au moins, au sein de votre propre code. Ceci élimine complètement le problème de la mémoire de la perspective, de toute façon. Évidemment, les objets en mouvement et a un coût. En réalité, vous ne vraiment avoir un problème si vous allouez de très petites quantités hors du tas souvent. À l'aide de contiguë conteneurs (vecteur, chaîne de caractères, etc) et de l'allocation sur la pile d'autant qu'il est humainement possible (toujours une bonne idée de la performance) est le meilleur moyen de le réduire. Cela augmente également la cohérence de cache, ce qui permet à votre application de fonctionner plus rapidement.
Ce que vous devez retenir, c'est que sur un 32 bits x86 système de bureau, vous avez un ensemble de 2 go de mémoire, qui est divisé en 4 KO "pages" (sûr la taille de la page est le même sur tous les systèmes x86). Vous aurez pour appeler certains omgwtfbbq la fragmentation d'avoir un problème. La Fragmentation est vraiment une question du passé, depuis modernes tas sont trop grandes pour la grande majorité des applications, et il y a une prévalence de systèmes qui sont capables de résister à cela, comme la gestion de monceaux.