TL;
Allocation Stack vs Allocation Boxed
Ceci est peut-être plus nette:
- bâton à la pile,
- À moins que la valeur est assez grand qu'il soufflerait vers le haut.
Alors que sémantiquement écriture fn foo() -> Bar
implique le transfert Bar
du cadre callee au cadre de l'appelant, en pratique, vous êtes plus susceptibles de se retrouver avec l'équivalent d'une signature fn foo(__result: mut * Bar)
où l'appelant alloue de l'espace sur sa pile et passe un pointeur vers l'appelé.
Cela peut ne pas toujours être suffisante pour éviter la copie, car certains modèles peuvent empêcher d'écrire directement dans la fente de retour:
fn defeat_copy_elision() -> WithDrop {
let one = side_effectful();
if side_effectful_too() {
one
} else {
side_effects_hurt()
}
}
Ici, il n'y a pas de magie:
- si l'utilisation du compilateur l'emplacement de retour pour
one
, puis dans le cas où la branche évalue à false
il doit se déplacer one
puis instancier le nouveau WithDrop
dedans, et enfin détruire one
,
- Si le compilateur instancie
one
sur la pile en cours et qu'il doit le renvoyer, il doit effectuer une copie.
Si le type n'avait pas besoin de Drop
, il n'y aurait pas de problème.
Malgré ces cas bizarres, je conseille de coller à la pile si possible, sauf si le profilage révèle un endroit où il serait avantageux de mettre en boîte.
Inline membre ou Boxed Membre
Cette affaire est beaucoup plus compliquée:
la taille du struct
/enum
est affecté, ainsi le comportement du cache du processeur est affectée:
- moins fr les grandes variantes utilisées régulièrement sont un bon candidat pour la boxe (ou les parties de boxe d'entre eux),
- les membres les moins fréquemment accédés sont un bon candidat pour la boxe.
en même temps, il y a des coûts pour la boxe:
- il est incompatible avec
Copy
types, et met en œuvre implicitement Drop
(qui, comme on le voit ci-dessus, désactive certaines optimisations),
- allouant/freeing la mémoire a un temps de latence illimité ,
- L'accès à la mémoire boîte introduit une dépendance aux données: vous ne pouvez pas savoir quelle ligne de cache demander avant de connaître l'adresse.
En conséquence, c'est un équilibre très fin. Boxe ou unboxing un membre peut améliorer les performances de certaines parties de la base de code tout en diminuant les performances des autres.
Il n'y a définitivement pas de taille unique.
Ainsi, encore une fois, je conseille d'éviter la boxe jusqu'à ce que le profilage révèle un endroit où il serait bénéfique de boxer.
Tenir compte que sur Linux, toute allocation de mémoire pour laquelle il n'y a pas de mémoire de rechange dans le processus peut nécessiter un appel système qui, s'il n'y a pas de mémoire de rechange dans le système d'exploitation peut déclencher le tueur OOM tuer un processus, à quel point sa mémoire est récupérée et rendue disponible. Un simple malloc(1)
peut facilement exiger millisecondes.