Est-il préférable d’allouer de la mémoire à deux ou plus?

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

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

S’il vaut mieux donner la taille qui est au pouvoir de deux, quelle en est la raison? Pourquoi est-ce mieux?

Merci

modifier

La raison de ma confusion est la citation du blog de Joel Retour aux bases

Les programmeurs intelligents minimisent la distorsion potentielle de malloc en allouant toujours des blocs de mémoire d’une puissance de 2. Vous savez, 4 octets, 8 octets, 16 octets, 18446744073709551616 octets, etc. Pour des raisons qui devraient être intuitives pour quiconque joue avec Lego, cela minimise la quantité de fragmentation étrange qui se produit dans la chaîne libre. Bien que cela puisse sembler gaspiller de l’espace, il est également facile de voir comment il ne gaspille jamais plus de 50% de l’espace. Ainsi, votre programme n’utilise pas plus de deux fois plus de mémoire que nécessaire, ce qui n’est pas une grosse affaire.

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

La plupart des réponses, jusqu’à présent, disent que l’allocation de mémoire au pouvoir de deux est une mauvaise idée, alors dans quel scénario il vaut mieux suivre le sharepoint Joel sur malloc() ? Pourquoi a-t-il dit ça? La suggestion citée ci-dessus est-elle obsolète maintenant?

Veuillez l’expliquer.
Merci

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

Cependant, toute implémentation non sortingviale de malloc qui se préoccupe d’être efficace arrondira les allocations de cette manière si et quand cela est approprié. Vous n’avez pas besoin de vous soucier “d’aider” malloc; malloc peut très bien se débrouiller tout seul.

Modifier:

En réponse à votre citation de l’article de Joel on Software, le sharepoint Joel dans cette section (difficile à discerner correctement sans le contexte qui suit le paragraphe que vous avez cité) est que si vous souhaitez réallouer fréquemment un tampon, préférable de le faire de manière multiplicative plutôt qu’additive. C’est en fait exactement ce que font les classes std::ssortingng et std::vector de C ++ (entre autres).

La raison pour laquelle ceci est une amélioration n’est pas parce que vous aidez malloc en fournissant des numéros pratiques, mais parce que l’allocation de mémoire est une opération coûteuse et que vous essayez de minimiser le nombre de fois que vous le faites. Joel présente un exemple concret de l’idée d’un compromis spatio-temporel. Il fait valoir que, dans de nombreux cas, la quantité de mémoire nécessaire change dynamicment, il est préférable de gaspiller de l’espace (en allouant jusqu’à deux fois plus de ressources nécessaires à chaque extension) afin de gagner du temps. sur exactement n octets de mémoire, chaque fois que vous avez besoin de n octets supplémentaires.

Le multiplicateur ne doit pas nécessairement être deux: vous pouvez allouer jusqu’à trois fois plus d’espace que nécessaire et obtenir des allocations de trois ou allouer jusqu’à cinquante-cinq fois plus d’espace que nécessaire. avec des atsortingbutions en pouvoirs de cinquante-sept. Plus vous faites de surallocation, moins vous aurez besoin de les réaffecter fréquemment, mais plus vous perdrez de la mémoire. Allouer des puissances de deux, qui utilisent au maximum deux fois plus de mémoire que nécessaire, s’avère être un bon compromis jusqu’au sharepoint départ et à moins que vous ayez une meilleure idée de vos besoins.

Il mentionne en passant que cela consortingbue à réduire la “fragmentation de la chaîne libre”, mais la raison en est davantage du nombre et de l’uniformité des atsortingbutions effectuées que de 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 que vous allouez. Deuxièmement, si vous redimensionnez dynamicment plusieurs tampons en utilisant le même algorithme de redimensionnement multiplicatif, il est probable que si l’on redimensionne de 32 à 64, et qu’un autre redimensionne de 16 à 32, la réallocation du second l’habitude d’être. Ce ne serait pas le cas si on redimensionnait 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.

Pour jouer à l’avocat du diable, voici comment Qt le fait:

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

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

QSsortingng alloue 4 caractères à la fois jusqu’à ce qu’il atteigne la taille 20. De 20 à 4084, il avance en doublant la taille à chaque fois. Plus précisément, il passe à la puissance suivante de deux, moins 12. ( Certains allocateurs de mémoire effectuent les pires performances à la demande de puissances de deux , car ils utilisent quelques octets par bloc pour la comptabilité). de 2048 caractères (4096 octets). Cela est logique car les systèmes d’exploitation modernes ne copient pas la totalité des données lors de la réallocation d’un tampon . les pages de mémoire physique sont simplement réorganisées et seules les données des première et dernière pages doivent être copiées.

J’aime la manière dont ils anticipent les fonctionnalités du système d’exploitation dans un code destiné à être performant des smartphones aux batteries de serveurs. Étant donné qu’ils sont plus intelligents que moi, je suppose que cette fonctionnalité est disponible dans tous les systèmes d’exploitation modernes.

Cela aurait pu être vrai une fois, mais ce n’est certainement pas mieux.

Allouez simplement la mémoire dont vous avez besoin, lorsque vous en avez besoin et libérez-la dès que vous avez terminé.

Il y a beaucoup trop de programmes qui débordent de ressources – ne faites pas le vôtre.

C’est un peu hors de propos.

Malloc alloue en réalité un peu plus de mémoire que ce que vous demandez, car il a ses propres en-têtes à traiter. Par conséquent, le stockage optimal est probablement quelque chose comme 4 4k-12 octets … mais cela varie en fonction de l’implémentation.

Dans tous les cas, il n’ya aucune raison pour que vous obteniez plus de stockage que nécessaire.

Vous souhaiterez peut -être allouer de la mémoire en termes de taille de mot du processeur; aucune puissance ancienne de 2 ne le fera.

Si le processeur dispose d’un mot de 32 bits (4 octets), allouez-le en unités de 4 octets. L’atsortingbution de 2 octets peut ne pas être utile car le processeur préfère que les données démarrent sur une limite de 4 octets.

Par contre, cela peut être une micro-optimisation. La plupart des bibliothèques d’allocation de mémoire sont configurées pour renvoyer la mémoire alignée au bon endroit et laisser le moins de fragmentation possible. Si vous allouez 15 octets, la bibliothèque peut étendre et allouer 16 octets. 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 / gestionnaire d’allocation gérer le montant réel pour vous. Mettez plus d’énergie dans la correction et la robustesse que de vous soucier de ces problèmes insignifiants.

Lorsque j’alloue un tampon qui peut avoir besoin de croître pour prendre en charge des données de taille encore inconnue, je commence avec une puissance de 2 moins 1 et chaque fois qu’il manque d’espace, je réalloue à deux fois la taille précédente. plus 1. Cela fait en sorte que je n’ai jamais à me soucier des débordements d’entiers; la taille ne peut être dépassée que lorsque la taille précédente était SIZE_MAX. À ce stade, l’allocation aurait déjà échoué, et de toute façon, 2*SIZE_MAX+1 == SIZE_MAX .

En revanche, si je viens d’utiliser une puissance de 2 et de la doubler à chaque fois, je parviendrai peut-être à obtenir un tampon de 2 à 31 octets, puis à réatsortingbuer un tampon de 0 octet à la prochaine fois.

Comme certaines personnes ont fait remarquer que la puissance de 2-moins-12 était bonne pour certaines implémentations malloc, on pourrait également commencer avec une puissance de 2 moins 12, puis doubler et append 12 à chaque étape …

D’un autre côté, si vous allouez simplement de petits tampons qui n’ont pas besoin d’être développés, demandez exactement la taille dont vous avez besoin. N’essayez pas de deviner ce qui est bon pour malloc.

Ceci est totalement dépendant de l’implémentation libc donnée de malloc(3) . C’est à cette implémentation de réserver des morceaux de tas dans l’ordre de leur choix.

Pour répondre à la question – non, ce n’est pas “mieux” (ici par “mieux” tu veux dire …?). Si la taille que vous demandez est trop petite, malloc(3) réservera un plus gros morceau en interne, respectez donc votre taille exacte.

Avec la quantité de mémoire d’aujourd’hui et sa vitesse, je ne pense plus que ce soit pertinent.

De plus, si vous allouez de la mémoire fréquemment, vous feriez mieux d’envisager un pool / pré-allocation de mémoire personnalisée.

Il y a toujours des tests …

Vous pouvez essayer un programme “exemple” qui alloue de la mémoire dans une boucle. De cette façon, vous pouvez voir si votre compilateur alloue comme par magie de la mémoire en puissances de 2. Avec cette information, vous pouvez essayer d’allouer la même quantité de mémoire totale en utilisant les 2 stratégies: blocs de taille aléatoire et puissance de 2 blocs.

Je m’attendrais seulement à des différences, le cas échéant, pour de grandes quantités de mémoire.

Si vous allouez une sorte de mémoire tampon extensible où vous devez choisir un nombre pour les allocations initiales, alors oui, les puissances de 2 sont de bons nombres à choisir. Si vous avez besoin d’allouer de la mémoire pour struct foo, alors seulement malloc (sizeof (struct foo)). La recommandation pour les allocations de puissance 2 découle de l’inefficacité de la fragmentation interne, mais les implémentations malloc modernes destinées aux systèmes multiprocesseurs commencent à utiliser des pools locaux pour les allocations suffisamment petites, ce qui évite les conflits de locking habituels. Il en résulte que plusieurs threads tentent de faire des malloc en même temps et passent plus de temps bloqués en raison de la fragmentation.

En n’allouant que ce dont vous avez besoin, vous vous assurez que les structures de données sont plus compactes en mémoire, ce qui améliore le taux de réussite du cache, ce qui a un impact beaucoup plus important sur les performances que la fragmentation interne. Il existe des scénarios avec de très anciennes implémentations malloc et des systèmes multiprocesseurs très haut de gamme où les allocations de remplissage explicites peuvent fournir une accélération, mais vos ressources dans ce cas seraient mieux utilisées pour obtenir une meilleure implémentation malloc sur ce système. Le pré-remplissage rend également votre code moins portable et empêche l’utilisateur ou le système de sélectionner le comportement malloc au moment de l’exécution, par programmation ou avec des variables d’environnement.

L’optimisation prématurée est la racine de tout Mal.

Vous devez utiliser realloc () au lieu de malloc () lors de la réallocation. http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/

Toujours utiliser une puissance de deux? Cela dépend de ce que fait votre programme. Si vous avez besoin de retraiter toute votre structure de données quand elle devient deux fois plus puissante, oui, c’est logique. Sinon, atsortingbuez simplement ce dont vous avez besoin et n’utilisez pas de mémoire.