Pile vs allocation de tas de structures en Aller, et comment ils se rapportent à la collecte des déchets
Je suis nouveau à l'Aller, et je suis en train de vivre un peu de congitive dissonance entre C-style basée sur la pile de programmation où les variables automatiques en direct sur la pile et de la mémoire allouée vie sur le tas et et Python de style basée sur la pile de programmation où la seule chose qui vit sur la pile sont des références/pointeurs vers des objets sur le tas.
Aussi loin que je peux dire, les deux fonctions suivantes, donner le même résultat:
func myFunction() (*MyStructType, error) {
var chunk *MyStructType = new(HeaderChunk)
...
return chunk, nil
}
func myFunction() (*MyStructType, error) {
var chunk MyStructType
...
return &chunk, nil
}
c'est à dire affecter une nouvelle structure et de le retourner.
Si j'avais écrit que, dans C, le premier aurait mis un objet sur le tas et la deuxième serait de le mettre sur la pile. La première serait de retourner un pointeur sur le tas, la seconde à retourner un pointeur sur la pile, ce qui aurait évaporé, le temps que la fonction était de retour, ce qui serait une Mauvaise Chose.
Si j'avais écrit en Python (ou de beaucoup d'autres langues modernes à l'exception de C#) exemple 2 n'aurait pas été possible.
- Je obtenir Aller à déchets collecte à la fois les valeurs, de sorte que les deux formes sont très bien.
Citer:
Noter que, contrairement au C, il est parfaitement OK pour retourner à l'adresse d'un
variable locale; le stockage associé à la variable survit
après le retour de fonction. En fait, prendre l'adresse d'un composite
littéral alloue une nouvelle instance à chaque fois qu'il est évalué, de sorte que nous
pouvez combiner ces deux dernières lignes.
Mais il soulève quelques questions.
1 - Dans l'exemple 1, la structure est déclarée sur le tas. Qu'en est l'exemple 2? C'est que déclaré sur la pile de la même façon qu'en C ou faut-il aller sur le tas trop?
2 - Si l'exemple 2 est déclaré sur la pile, comment fait-il pour rester disponibles après la fonction retourne?
3 - Si l'exemple 2 est effectivement déclaré sur le tas, comment est-ce que les structures sont passés par valeur plutôt que par référence? Quel est le point de pointeurs dans ce cas?
Vous devez vous connecter pour publier un commentaire.
Il est intéressant de noter que les mots "pile" et "tas" n'apparaissent pas dans la langue spec. Votre question est formulée avec "...est déclaré sur la pile", et "...a déclaré sur le tas", mais note que Aller syntaxe de déclaration ne dit rien sur la pile ou le tas.
Qui techniquement fait la réponse à toutes vos questions dépendant de l'implémentation. En réalité, bien sûr, il y a une pile (par goroutine!) et un tas et certaines choses aller sur la pile et certains sur le tas. Dans certains cas, le compilateur respecte les règles rigides (comme "
new
alloue toujours sur le tas") et dans d'autres, le compilateur ne "s'échapper d'analyse" pour décider si un objet peut vivre sur la pile ou si elle doit être alloué sur le tas.Dans votre exemple 2, échapper à l'analyse d'afficher le pointeur vers la structure de fuir et de sorte que le compilateur aurait allouer de la struct. Je pense que l'actuelle mise en œuvre de Go suit une règle rigide, dans ce cas, cependant, qui est que si l'adresse est prise de toute partie d'une structure, la structure va sur le tas.
Pour la question 3, on risque de se confondre sur la terminologie. Tout de Go est passé par valeur, il n'y a pas de passage par référence. Ici vous retournent une valeur de type pointeur. Quel est le point de pointeurs? Considérons la suite de la modification de votre exemple:
J'ai modifié myFunction2 pour revenir à la structure plutôt que l'adresse de la structure. Comparer l'assemblée de sortie de myFunction1 et myFunction2 maintenant,
Ne vous inquiétez pas que myFunction1 de sortie ici est différente de celle de peterSO de la (bonne) réponse. Nous sommes évidemment l'exécution de différents compilateurs. Sinon, de voir que je transforme myFunction2 de retour myStructType plutôt que *myStructType. L'appel à l'exécution.les nouvelles est allé, qui, dans certains cas, serait une bonne chose. Tenir sur bien, voici myFunction3,
Toujours pas d'appel pour l'exécution.nouvelle, et oui, il fonctionne vraiment pour retourner un 8MB objet par valeur. Il fonctionne, mais vous ne voulez pas. Le point d'un pointeur ici serait d'éviter de pousser autour de 8 MO objets.
Dans les deux cas, les implémentations actuelles de Go serait d'allouer de la mémoire pour un
struct
de typeMyStructType
sur un segment de mémoire et retourne son adresse. Les fonctions sont équivalentes; le compilateur asm source est la même.Toutes les fonctions et de revenir les paramètres sont passés par valeur. Le paramètre de retour de la valeur avec le type
*MyStructType
est une adresse.Selon Go FAQ:
Source: http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#stack_heap_vars