Existe-t-il un moyen d'allouer de la mémoire sur pile au lieu de tas ? Je n'arrive pas à trouver un bon livre sur ce sujet, quelqu'un ici a une idée ?
Le problème ici est que de nombreux objets C++ s'allouent de la mémoire pour eux-mêmes.
Existe-t-il un moyen d'allouer de la mémoire sur pile au lieu de tas ? Je n'arrive pas à trouver un bon livre sur ce sujet, quelqu'un ici a une idée ?
Utilisez alloca()
(parfois appelé _alloca()
o _malloca()
), mais soyez très prudent à ce sujet - il libère sa mémoire lorsque vous quittez une fonction, et non lorsque vous sortez du champ d'application, ce qui fait que vous allez rapidement exploser si vous l'utilisez à l'intérieur d'une boucle.
Par exemple, si vous avez une fonction comme
int foo( int nDataSize, int iterations )
{
for ( int i = 0; i < iterations ; ++i )
{
char *bytes = alloca( nDataSize );
// the memory above IS NOT FREED when we pass the brace below!
}
return 0;
} // alloca() memory only gets freed here
Ensuite, la fonction alloca() allouera un fichier supplémentaire nDataSize octets à chaque fois dans la boucle . Aucun des octets alloca() n'est libéré avant le retour de la fonction. Ainsi, si vous avez un nDataSize
de 1024 et un iterations
de 8, vous allouerez 8 kilo-octets avant de revenir. Si vous avez un nDataSize
= 65536 et iterations
= 32768, vous allouerez un total de 65536×32768=2 147 483 648 octets, ce qui fera presque certainement exploser votre pile et provoquera un crash.
anecdote : Vous pouvez facilement avoir des problèmes si vous écrivez au-delà de la fin du tampon, surtout si vous passez le tampon dans une autre fonction et que cette sous-fonction a une idée erronée de la longueur du tampon. J'ai une fois corrigé un bug plutôt amusant où nous utilisions alloca()
pour créer un stockage temporaire pour le rendu d'un glyphe de police TrueType avant de l'envoyer dans la mémoire du GPU. Notre bibliothèque de polices n'a pas pris en compte le diacritique du caractère suédois Å lors du calcul de la taille des glyphes, et nous a donc demandé d'allouer la mémoire du GPU à la police TrueType. n octets pour stocker le glyphe avant le rendu, puis effectivement rendu n +128 octets. Les 128 octets supplémentaires ont été écrits dans la pile d'appel, écrasant l'adresse de retour et provoquant un crash non déterministe très douloureux !
Comme il s'agit de C++ balisé, il suffit généralement de déclarer les objets dont on a besoin dans la bonne portée. Ils sont alloués sur la pile, et leur libération est garantie à la sortie de la portée. Ceci est RAII et un avantage essentiel de C++ par rapport à C. Non malloc
ou new
et surtout pas de alloca
s, nécessaires.
@Zan Lynx - c'est sûr. Mais dans quel scénario alloueriez-vous un tel graphe d'objets sur la pile ?
Vous pouvez appeler une fonction qui remplit un vecteur. Vous pouvez avoir besoin d'une chaîne de caractères. Vous pouvez avoir besoin que ces choses soient très rapides et sans risque pour les threads. Si vous n'avez pas besoin que ces choses vivent au-delà de la fonction, alors le stockage en pile est exactement le bon endroit.
Vous pouvez déclarer un char[1024]
ou le nombre d'octets que vous souhaitez (jusqu'à un certain point), puis prenez l'adresse du local pour un pointeur vers ce bloc de mémoire sur la pile. Ce n'est pas exactement dynamique, mais vous pouvez ensuite envelopper cette mémoire avec votre propre gestionnaire de mémoire si vous le souhaitez.
Ce devrait être la deuxième meilleure réponse à cette question spécifique, si ce n'est la réponse acceptée. Elle est propre et simple, contrairement à la réponse _alloca.
Article traitant de l'allocation dynamique de la mémoire
Nous pouvons allouer dynamiquement de l'espace de longueur variable sur la mémoire de la pile en utilisant la fonction _alloca. Cette fonction alloue de la mémoire à partir de la pile du programme. Elle prend simplement le nombre d'octets à allouer et retourne void* à l'utilisateur. l'espace alloué tout comme l'appel malloc. Cette mémoire allouée sera libérée automatiquement à la sortie de la fonction.
Il n'est donc pas nécessaire de le libérer explicitement. Il faut garder à l'esprit la taille taille de l'allocation, car une exception de débordement de pile peut se produire. Pile peut être utilisé pour de tels appels. En cas de exception de débordement de pile, on peut utiliser
_resetstkoflw()
pour le restaurer retour.Ainsi, notre nouveau code avec
_alloca
serait :int NewFunctionA() { char* pszLineBuffer = (char*) _alloca(1024*sizeof(char)); ….. // Program logic …. //no need to free szLineBuffer return 1; }
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
0 votes
Si vous souhaitez contrôler l'endroit où un std::string ou un std::vector alloue sa mémoire, consultez cette question : stackoverflow.com/questions/354442/
1 votes
@Neil : pour allouer/libérer rapidement un espace de travail temporaire ?
0 votes
@Neil Butterworth Exemple : vous devez allouer une quantité variable d'espace pour un tampon temporaire pendant que vous triez les sommets par profondeur. Les sommets proviennent de données d'exécution, vous ne savez donc pas à l'avance combien vous en aurez. De plus, vous disposez d'un budget de 2 microsecondes pour l'ensemble de la fonction, et sur votre plate-forme, malloc() coûte 1 microseconde.
0 votes
@Andre Il suffit donc de créer des objets locaux comme d'habitude - pas besoin d'installations spéciales.
0 votes
Zan : Je ne pense pas que tu puisses implémenter un allocateur qui utilise
alloca
. La mémoire allouée ne peut être utilisée qu'à l'intérieur de la fonction qui l'a allouée, donc le tampon ne peut pas être retourné depuis l'allocateur !2 votes
@Neil : et si la fonction a besoin d'un nombre réduit, mais variable, d'objets temporaires ? Vous pourriez utiliser un
vector
Mais si cette fonction est invoquée dans une boucle serrée, il serait intéressant que la mémoire puisse être rapidement allouée et libérée sans se soucier de la fragmentation.0 votes
@André : La réponse acceptée à cette question n'implique pas l'alloca.
0 votes
@Zan : ce que le PO a demandé implique nécessairement
alloca
.1 votes
@Andre - Puis allouer un petit nombre, mais fixe, d'objets sur la pile. Si nous ne connaissons pas la limite supérieure, alloca explosera de toute façon.
0 votes
@André : Il y a un lot de questions sur StackOverflow où la question posée n'est pas ce dont le questionneur a réellement besoin.
0 votes
@Bo : bien sûr, mais cela introduit un nombre magique supplémentaire dans le code, et la limite varie en fonction de la machine, des drapeaux du compilateur, etc. (tout ce qui peut influencer la taille de la pile). Si j'augmente la taille de la pile, je devrais maintenant modifier deux ensembles de paramètres : la taille réelle de la pile, le nombre d'heures de travail et le nombre d'heures de travail. y la limite codée en dur pour ma fonction.
0 votes
std::queue
et la récursion peut-être car cet objet est conçu pour une allocation rapide et continue. Remarque en C++new
ydelete
sont utilisés pour l'allocation du tas, peut-être que cela devrait être ré-étiqueté comme C.0 votes
@Neil :
alloca
est largement utilisé dans Microsoft Windows, pour les tampons temporaires de chaîne de caractères pour la traduction entre UTF-16 et Windows ANSI.1 votes
@Alf Je programme pour Windows depuis 2.0 et je ne l'ai jamais utilisé, ou vu utilisé..,
0 votes
@Neil : Je suppose que tous ces appels sont cachés dans les versions ANSI de l'interface Win32API, puisque le noyau ne traite que les versions Unicode.
0 votes
@Neil : comme le dit André. De plus, pour votre propre usage, si je me souviens bien, MFC et ATL définissent une série de macros qui regroupent les éléments suivants
alloca
appels. Je peux chercher si tu veux, mais comme je sais que tu es plutôt bon, je ne perds pas de temps avec ça pour l'instant. Santé,0 votes
Voir stackoverflow.com/questions/354442/