40 votes

Est-il préférable d'allouer la mémoire en puissance de deux ?

Lorsque nous utilisons malloc() pour allouer de la mémoire, doit-on donner la taille qui est en puissance de deux ? Ou devons-nous simplement donner la taille exacte dont nous avons besoin ?
Comme

//char *ptr= malloc( 200 ); 
char *ptr= malloc( 256 );//instead of 200 we use 256

S'il est préférable de donner une taille qui est à la puissance deux, quelle en est la raison ? Pourquoi est-ce mieux ?

Merci

Modifier

La raison de ma confusion est la citation suivante tirée du blog de Joel Retour à l'essentiel

Les programmeurs intelligents minimisent la perturbation potentielle de malloc en allouant toujours des blocs de mémoire qui sont des puissances de 2 en taille. Vous vous savez, 4 octets, 8 octets, 16 octets, 18446744073709551616 octets, etc. Pour raisons qui devraient être intuitives pour toute personne qui joue avec des Lego, cela minimise la quantité d'étrange fragmentation bizarre qui se produit dans la libre. Bien qu'il puisse sembler que cela gaspille de l'espace, il est également facile de voir comment cela ne gaspille jamais plus de 50% de de l'espace. Donc votre programme n'utilise pas plus de deux fois plus de mémoire qu'il n'en utilise nécessaire, ce qui n'est pas si grave. problème.

Désolé, j'aurais dû poster la citation ci-dessus plus tôt. Toutes mes excuses !

La plupart des réponses, jusqu'à présent, disent que l'allocation de la mémoire à la puissance deux est une mauvaise idée, alors dans quel scénario il est préférable de suivre le point de Joel sur malloc() ? Pourquoi a-t-il dit cela ? La suggestion citée ci-dessus est-elle désormais obsolète ?

Veuillez l'expliquer.
Merci

54voto

Tyler McHenry Points 35551

Indiquez simplement la taille exacte dont vous avez besoin. La seule raison pour laquelle une taille à la puissance deux pourrait être "meilleure" est de permettre une allocation plus rapide et/ou d'éviter la fragmentation de la mémoire.

Cependant, tout non-trivial malloc Une implémentation qui se préoccupe d'être efficace va arrondir les allocations de manière interne de cette façon si et quand il est approprié de le faire. Vous n'avez pas besoin de vous préoccuper d'"aider" malloc ; malloc peut très bien se débrouiller tout seul.

Edit :

En réponse à votre citation de l'article de Joel sur les logiciels, le point de vue de Joel dans cette section (qui est difficile à discerner correctement sans le contexte qui suit le paragraphe que vous avez cité) est que si vous vous attendez à ce que les logiciels soient fréquemment utilisés, vous ne devez pas les utiliser. concernant -allouer un tampon, il est préférable de le faire de manière multiplicative, plutôt que de manière additive. C'est, en fait, exactement ce que fait le std::string y std::vector en C++ (entre autres) le font.

La raison pour laquelle c'est une amélioration n'est pas parce que vous aidez malloc en fournissant des chiffres pratiques, mais parce que l'allocation de la mémoire est une coûteux et vous essayez de minimiser le nombre de fois où vous le faites. Joel présente un exemple concret de l'idée d'un compromis temps-espace. Il soutient que, dans de nombreux cas où la quantité de mémoire nécessaire change dynamiquement, il est préférable de gaspiller un peu d'espace (en allouant jusqu'à deux fois plus que ce dont vous avez besoin à chaque expansion) afin d'économiser le temps et l'espace. temps qui serait nécessaire pour ajouter à plusieurs reprises exactement n octets de mémoire, à chaque fois que vous avez besoin n plus d'octets.

Le multiplicateur ne doit pas nécessairement être égal à deux : vous pouvez allouer jusqu'à trois fois plus d'espace que nécessaire et obtenir des allocations en puissance de trois, ou allouer jusqu'à cinquante-sept fois plus d'espace que nécessaire et obtenir des allocations en puissance de cinquante-sept. Plus vous faites de surallocation, moins vous devrez réallouer fréquemment, mais plus vous gaspillerez de mémoire. L'allocation en puissances de deux, qui utilise au maximum deux fois plus de mémoire que nécessaire, se trouve être un bon compromis de départ jusqu'à ce que vous ayez une meilleure idée de vos besoins exacts.

Il mentionne au passage que cela permet de réduire la "fragmentation dans la chaîne libre", mais la raison en est davantage le nombre et l'uniformité des allocations effectuées, plutôt que leur taille exacte. D'une part, plus vous allouez et désallouez de la mémoire, plus vous risquez de fragmenter le tas, quelle que soit la taille de l'allocation. Deuxièmement, si vous avez plusieurs tampons que vous redimensionnez dynamiquement à l'aide du même algorithme de redimensionnement multiplicatif, il est probable que si l'un passe de 32 à 64, et un autre de 16 à 32, la réaffectation du second peut s'adapter à la place du premier. Ce ne serait pas le cas si l'un passait de 25 à 60 et l'autre de 16 à 26.

Et encore une fois, rien de ce dont il parle ne s'applique si vous ne faites l'étape d'allocation qu'une seule fois.

18voto

György Andrasek Points 4332

Juste pour se faire l'avocat du diable, voici comment Qt le fait :

Supposons que nous ajoutons 15000 à la chaîne QString. Ensuite, les 18 réaffectations suivantes (sur une 15000 possibles) se produisent lorsque QString manque d'espace : 4, 8, 12, 16, 20, 52, 116, 244, 500, 1012, 2036, 4084, 6132, 8180, 10228, 12276, 14324, 16372. A la fin, la QString a 16372 caractères Unicode alloués, dont 15000 sont occupés.

Les valeurs ci-dessus peuvent sembler un peu étrange, mais voici les principes directeurs principes directeurs :

La chaîne QString alloue 4 caractères à la fois jusqu'à ce qu'elle atteigne la taille 20. De 20 à 4084, elle avance en doublant chaque fois la taille à chaque fois. Plus précisément, elle avance à la prochaine puissance de deux, moins 12. ( Certains allocateurs de mémoire sont moins performants lorsqu'on leur demande des puissances de deux parce qu'ils utilisent quelques octets par bloc pour la tenue des comptes). À partir de 4084, il avance par blocs de 2048 caractères (4096 octets). Le site logique car Les systèmes d'exploitation modernes Les systèmes d'exploitation modernes ne copient pas l'intégralité des données lors de la réaffectation d'un tampon ; les pages de mémoire physique sont simplement simplement réorganisées, et seules les données des première et dernière pages doivent réellement être être copiées.

J'aime la façon dont ils anticipent les caractéristiques des systèmes d'exploitation dans un code qui est censé être performant, des smartphones aux fermes de serveurs. Étant donné que ce sont des gens plus intelligents que moi, je suppose que cette fonctionnalité est disponible dans tous les systèmes d'exploitation modernes.

6voto

ChrisF Points 74295

Il pourrait a été vrai autrefois, mais ce n'est certainement pas mieux.

Il suffit d'allouer la mémoire dont vous avez besoin, quand vous en avez besoin et de la libérer dès que vous avez terminé.

Il y a beaucoup trop de programmes qui sont prodigues en ressources - ne faites pas du vôtre l'un d'entre eux.

4voto

Chris Arguin Points 6469

C'est un peu hors sujet.

Malloc alloue en fait un peu plus de mémoire que ce que vous demandez, car il doit s'occuper de ses propres en-têtes. Par conséquent, le stockage optimal est probablement quelque chose comme 4k-12 octets... mais cela varie en fonction de l'implémentation.

Dans tous les cas, il n'y a aucune raison pour que vous arrondissiez à plus de stockage que nécessaire comme technique d'optimisation.

2voto

Thomas Matthews Points 19838

Vous mai Il faut allouer la mémoire en fonction de la taille des mots du processeur, et non pas en fonction de n'importe quelle puissance de 2.

Si le processeur a un mot de 32 bits (4 octets), alors l'allocation se fait par unités de 4 octets. L'allocation en termes de 2 octets peut ne pas être utile car le processeur préfère que les données commencent sur une frontière de 4 octets.

D'un autre côté, il peut s'agir d'une micro-optimisation. La plupart des bibliothèques d'allocation de mémoire sont configurées pour retourner de la mémoire alignée à la bonne position et qui laissera le moins de fragmentation possible. Si vous allouez 15 octets, la bibliothèque peut en allouer 16. Certains allocateurs de mémoire ont des pools différents en fonction de la taille de l'allocation.

En résumé, allouez la quantité de mémoire dont vous avez besoin. Laissez la bibliothèque ou le gestionnaire d'allocation gérer la quantité réelle pour vous. Mettez plus d'énergie dans la correction et la robustesse que de vous soucier de ces questions triviales.

Prograide.com

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.

Powered by:

X