Quelles sont les différences entre VirtualAlloc et HeapAlloc?

Il ya beaucoup de méthode pour allouer la mémoire dans L'environnement Windows, tels que VirtualAlloc , HeapAlloc , malloc , new .

donc, quelle est la différence entre eux?

72
demandé sur Ajay 2009-05-16 13:38:41

6 réponses

chaque API est destinée à des usages différents. Chacun d'eux exige également que vous utilisiez la fonction de désallocation/libération correcte lorsque vous avez terminé avec la mémoire.

VirtualAlloc

une API Windows de bas niveau qui fournit beaucoup d'options, mais est principalement utile pour les personnes dans des situations assez spécifiques. Ne peut allouer de mémoire qu'en (éditer: pas 4KB) gros morceaux. Il y a des situations où tu en as besoin, mais tu le sauras quand tu seras dans l'une de ces situations. situation. Un des plus communs est si vous devez partager la mémoire directement avec un autre processus. Ne l'utilisez pas pour l'attribution de la mémoire à usage général. Utilisez VirtualFree pour désallouer.

HeapAlloc

attribue quelle que soit la taille de la mémoire que vous demandez, pas en gros morceaux que VirtualAlloc . HeapAlloc sait quand il doit appeler VirtualAlloc et le fait automatiquement pour vous. Comme malloc , mais est Windows-seulement, et fournit un couple plus option. Convient à l'attribution de morceaux généraux de mémoire. Certains API Windows peuvent exiger que vous utilisiez ceci pour allouer la mémoire que vous leur transmettez, ou utiliser son compagnon HeapFree pour libérer la mémoire qu'ils vous rendent.

malloc

comme en C de l'allocation de mémoire. Préférez cela si vous écrivez en C plutôt qu'en C++, et vous voulez que votre code fonctionne aussi sur des ordinateurs Unix par exemple, ou que quelqu'un vous dise expressément que vous devez l'utiliser. Ne pas initialiser la mémoire. Convient pour allouer des morceaux généraux de mémoire, comme HeapAlloc . Une API simple. Utilisez free pour désallouer. Visual C++ malloc appels HeapAlloc .

nouveau

Le C++ moyen d'allouer de la mémoire. Préférez si vous écrivez en C++. Il met aussi un objet ou des objets dans la mémoire allouée. Utilisez delete pour désallouer (ou delete[] pour les tableaux). Appels new de Visual studio HeapAlloc , et puis peut-être initialise les objets, selon comment vous l'appelez.

dans les récentes normes C++ (C++11 et plus), si vous devez utiliser manuellement delete , vous le faites mal et vous devriez utiliser un pointeur intelligent comme unique_ptr à la place. A partir de C++14, on peut dire la même chose de new (remplacé par des fonctions telles que make_unique() ).


Il ya aussi un quelques autres fonctions similaires comme SysAllocString que l'on peut vous dire que vous devez utiliser dans des circonstances spécifiques.

74
répondu Doug 2017-03-17 17:22:29

VirtualAlloc est une allocation spécialisée du système de mémoire virtuelle (VM). Les Allocations dans le système VM doivent être faites à une granularité d'allocation qui (la granularité d'allocation) dépend de l'architecture. L'Allocation dans le système VM est l'une des formes les plus basiques d'allocation de mémoire. Les allocations de VM peuvent prendre plusieurs formes, la mémoire n'est pas nécessairement dédiée ou physiquement sauvegardée en RAM (bien qu'elle puisse l'être). L'allocation de VM est généralement un usage spécial type de répartition, soit en raison de la répartition doit

  • être très grande,
  • doit être partagé,
  • doit être aligné sur une valeur particulière (raisons de performance) ou
  • l'appelant n'a pas besoin d'utiliser toute cette mémoire en même temps...
  • etc...

HeapAlloc est essentiellement ce que malloc et new les deux finissent par appeler. Il est conçu pour être très rapide et utilisable dans de nombreux types de scénarios d'affectation générale. C'est le" tas " dans un sens classique. Les tas sont en fait établis par un VirtualAlloc , qui est ce qui est utilisé pour initialement espace d'allocation de réserve de L'OS. Une fois l'espace initialisé par VirtualAlloc , diverses tables, listes et autres structures de données sont configurées pour maintenir et contrôler le fonctionnement du tas. Une partie de cette opération prend la forme de dimensionnement dynamique (croissance et rétrécissement) du tas, d'adaptation du tas à des usages particuliers (allocations fréquentes d'une certaine taille), etc..

new et malloc sont en quelque sorte la même, malloc est essentiellement exact d'appeler HeapAlloc( heap-id-default ) ; new toutefois, [en outre] configurer la mémoire allouée pour le C++ objets . Pour un objet donné, C++ stockera vtables sur le tas pour chaque appelant. Ces vtables sont des redirections pour l'exécution et font partie de ce qui donne à C++ ses caractéristiques OO comme l'héritage, la surcharge de fonctions, etc...

quelques autres méthodes communes d'allocation comme _alloca() et _malloca() sont stack basé; FileMappings sont vraiment alloués avec VirtualAlloc et mis avec des indicateurs de bits particuliers qui désignent ces mappings d'être de type FILE .

la plupart des le temps, vous devez allouer de la mémoire dans une manière qui est compatible avec l'utilisation de la mémoire ;). new en C++, malloc C, VirtualAlloc pour massif ou de l'IPC cas.

* * * Note, de grandes allocations mémoire faites par HeapAlloc sont en fait expédiées à VirtualAlloc après une certaine taille (quelques centaines de k ou 16 Mo ou quelque chose que j'oublie, mais assez grand :) ).

* * * EDIT J'ai fait une brève remarque sur IPC et VirtualAlloc , Il ya aussi quelque chose de très soigné à propos d'un VirtualAlloc connexe dont aucun des répondants à cette question n'a discuté.

VirtualAlloc Ex est ce qu'un processus peut utiliser pour allouer la mémoire dans un espace d'adresse d'un processus différent . La plupart du temps, cela est utilisé en combinaison pour obtenir l'exécution à distance dans le contexte d'un autre processus via CreateRemoteThread (similaire à CreateThread , le thread est juste exécuté dans l'autre processus).

25
répondu RandomNickName42 2017-05-16 15:03:15

il est très important de comprendre la distinction entre les API d'allocation de mémoire (dans Windows) si vous prévoyez d'utiliser un langage qui nécessite une gestion de mémoire (comme C ou C++.) Et la meilleure façon de l'illustrer IMHO est avec un diagramme:

enter image description here

notez qu'il s'agit d'une vue très simplifiée, spécifique à Windows.

La façon de comprendre ce diagramme est que plus haut sur le diagramme une méthode d'allocation de mémoire est, le niveau supérieur mise en œuvre il utilise. Mais commençons par le bas.

Gestionnaire De Mémoire En Mode Noyau

il fournit toutes les réservations de mémoire et les allocations pour le système d'exploitation, ainsi que le soutien pour fichiers mémoire-mappés , mémoire partagée , copie-en-écriture opérations, etc. Il n'est pas directement accessible à partir du code du mode utilisateur, donc je vais le sauter ici.

VirtualAlloc / VirtualFree

ce sont les niveau le plus bas API disponibles à partir du mode utilisateur . La fonction VirtualAlloc invoque essentiellement ZwAllocateVirtualMemory qui à son tour fait un rapide syscall à ring0 à reléguer un traitement supplémentaire pour le gestionnaire de mémoire du noyau. C'est aussi la méthode la plus rapide pour réserver/allouer un bloc de mémoire disponibles dans le mode utilisateur.

mais il est livré avec deux conditions principales:

  • il n'attribue que des blocs de mémoire alignés sur la limite de granularité du système.

  • il attribue uniquement des blocs de mémoire de la taille qui est le multiple de la granularité du système.

alors c'est quoi granularité du système ? Vous pouvez l'obtenir en appelant GetSystemInfo . Il est retourné en tant que paramètre dwAllocationGranularity . Sa valeur est spécifique à l'implémentation (et peut-être au matériel), mais sur de nombreux systèmes Windows 64 bits, elle est fixée à 0x10000 octets, ou 64K .

donc ce que tout cela signifie, est que si vous essayez d'allouer, dire juste un bloc de mémoire de 8 octets avec VirtualAlloc :

void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

si le résultat est positif, pAddress sera aligné sur la limite des octets 0x10000 . Et même si vous avez demandé seulement 8 octets, le bloc de mémoire réel que vous obtiendrez sera le page entier (ou, quelque chose comme 4K octets. La taille exacte de la page est dwPageSize paramètre.) Mais, en plus de cela, l'intégralité du bloc mémoire couvrant 0x10000 octets (ou 64K dans la plupart des cas) de pAddress ne sera pas disponible pour d'autres attributions. Donc, en attribuant 8 octets, vous pourriez aussi bien demander 65536.

donc la morale de l'histoire ici n'est pas de remplacer VirtualAlloc par des allocations de mémoire génériques dans votre application. Il doit être utilisé pour des cas très spécifiques, comme c'est le cas avec le tas ci-dessous. (Généralement pour réserver/allouer de grands blocs de mémoire.)

L'utilisation incorrecte de VirtualAlloc peut entraîner une fragmentation sévère de la mémoire.

HeapCreate / HeapAlloc / HeapFree / HeapDestroy

en bref, les fonctions tas sont essentiellement une enveloppe pour la fonction VirtualAlloc . D'autres réponses ici de fournir un très bon concept. J'ajouterai que, d'un point de vue très simpliste, la façon dont tas fonctionne est celle-ci:

  • HeapCreate réserve un grand bloc de mémoire virtuelle en appelant VirtualAlloc en interne (ou ZwAllocateVirtualMemory pour être précis). Il établit également une base de données interne structure qui peut suivre d'autres allocations de plus petite taille dans le bloc réservé de la mémoire virtuelle.

  • les appels à HeapAlloc et HeapFree n'attribuent pas/ne libèrent pas de mémoire nouvelle (à moins, bien sûr, que la demande dépasse ce qui a déjà été réservé dans HeapCreate ) mais au lieu de cela ils meter out (ou commit ) un grand morceau précédemment réservé, en le disséquant en blocs de mémoire plus petits que un utilisateur demande.

  • HeapDestroy à son tour appelle VirtualFree qui libère réellement la mémoire virtuelle.

donc tout cela fait tas fonctions candidats parfaits pour les attributions génériques de mémoire dans votre application. Il est grand de taille arbitraire de l'allocation mémoire. Mais un petit prix à payer pour la commodité de la tas fonctions est que ils introduisent un léger over-over VirtualAlloc lors de la réservation de blocs de mémoire plus grands.

une autre bonne chose à propos de tas est que vous n'avez pas vraiment besoin d'en créer un. Il est généralement créé pour vous lorsque votre processus commence. On peut donc y accéder en appelant la fonction Getrocessheap .

malloc / libre

Est une langue spécifique enveloppe pour les fonctions tas . Contrairement à HeapAlloc , HeapFree , etc. ces fonctions de travail, non seulement si votre code est compilé pour Windows, mais aussi pour d'autres systèmes d'exploitation tels que Linux, etc.)

c'est une méthode recommandée pour allouer/libérer de la mémoire si vous programmez en C. (à moins que vous ne codiez un pilote de périphérique en mode noyau spécifique.)

nouveau / supprimer

Viennent comme un haut niveau (bien, pour C++ ) opérateurs de gestion de mémoire. Ils sont spécifiques pour la langue C++ , et comme malloc pour C , sont également les enveloppes pour les fonctions heap . Ils ont également tout un tas de leur propre code qui traite C++ -l'initialisation spécifique des constructeurs, la désallocation dans les destructeurs, etc.

ces fonctions sont un moyen recommandé pour allouer / libérer la mémoire et objets si vous programmez dans C++ .


enfin, je voudrais faire un commentaire sur ce qui a été dit dans d'autres réponses à propos de l'utilisation de VirtualAlloc pour partager la mémoire entre les processus. VirtualAlloc ne permet pas en soi de partager sa mémoire réservée/allouée avec d'autres processus. Pour cela, il faut utiliser CreateFileMapping API qui peut créer un bloc de mémoire virtuelle nommé qui peut être partagé avec d'autres processus. Il peut également mapper un fichier sur disque dans la mémoire virtuelle pour l'accès en lecture/écriture. Mais c'est un autre sujet.

13
répondu ahmd0 2017-05-18 19:32:38

Dans les grandes lignes:

  • VirtualAlloc, HeapAlloc etc. sont APIs Windows qui allouent la mémoire de divers types du système d'exploitation directement. VirtualAlloc gère les pages dans le système de mémoire virtuelle Windows, tandis que HeapAlloc attribue à partir d'un tas D'OS spécifique. Franchement, vous êtes peu probable qu'on ait besoin d'utiliser eiither d'entre eux.

  • malloc est une fonction de bibliothèque Standard C (et C++) qui attribue de la mémoire à votre processus. Les implémentations de malloc utiliseront généralement l'une des API OS pour créer un pool de mémoire lorsque votre application démarre, puis l'allouer à partir de celle-ci lorsque vous faites des requêtes malloc

  • new est un opérateur C++ Standard qui attribue de la mémoire puis appelle les constructeurs de façon appropriée sur cette mémoire. Il peut être implémenté en termes de malloc ou en termes D'API OS, auquel cas il créera aussi typiquement un pool de mémoire au démarrage de l'application.

6
répondu 2009-05-16 09:52:13

VirtualAlloc ===> sbrk() sous UNIX

HeapAlloc ====> malloc() sous UNIX

3
répondu Mrad Chems Eddine 2015-12-29 21:40:33

VirtualAlloc => Alloue directement dans la mémoire virtuelle, vous réserve de s'engager dans des blocs. C'est excellent pour les grandes attributions, par exemple les grands réseaux.

HeapAlloc / new => attribue la mémoire sur le tas par défaut (ou tout autre tas que vous pouvez créer). Il alloue par objet et est idéal pour les petits objets. Le tas par défaut est sérialisable donc il a l'allocation de thread de garantie (cela peut causer quelques problèmes sur la haute performance scénarios et c'est pourquoi vous pouvez créer votre propre tas).

malloc = > utilise le tas D'exécution C, similaire à HeapAlloc mais il est commun pour les scénarios de compatibilité.

en bref, le tas est juste un morceau de mémoire virtuelle qui est régie par un gestionnaire de tas (plutôt que la mémoire virtuelle brute)

le dernier modèle sur le monde de la mémoire est des fichiers cartographiés de mémoire, ce scénario est grand pour un gros morceau de données (comme de grandes fichier.) Ceci est utilisé en interne lorsque vous ouvrez un EXE (il ne charge pas L'EXE en mémoire, crée juste un fichier mappé en mémoire).

2
répondu No hay Problema 2015-12-29 21:41:30