2010-05-10 4 views
36

Je voudrais savoir comment les variables locales sont allouées en javascript. En C et C++, les variables locales sont stockées sur la pile. Est-ce la même chose en javascript? ou tout est stocké dans le tas?Comment les variables sont allouées de la mémoire en Javascript?

+0

duplication possible de [Est-ce que JavaScript a un tas de mémoire?] (Http://stackoverflow.com/questions/1026495/does-javascript-have-a-memory-heap) –

+2

Voir cet article, [A Tour of V8 : représentation d'objet] (http://www.jayconrod.com/posts/52/a-tour-of-v8-object-representation) qui fournit un aperçu de la façon dont le moteur Javascript V8 représente les objets Javascript. –

+0

@RichardChambers: Merci pour le gentil lien. –

Répondre

45

C'est en fait un domaine très intéressant de Javascript. Détails dans the spec, mais: la façon dont Javascript gère les variables locales est très différente de la façon dont C le fait. Quand vous appelez une fonction, entre autres choses, un "environnement variable" est créé pour cet appel, qui a quelque chose appelé "objet de liaison". (Appelez le "objet variable" pour faire court, dire "l'objet de liaison de l'environnement variable" est juste tad bit à long terme!) L'objet variable a propriétés pour les arguments de la fonction, toutes les variables locales déclaré dans la fonction, et toutes les fonctions déclarées dans la fonction (avec quelques autres choses). Les références non qualifiées (par exemple, foo dans foo, et non obj.foo) dans la fonction sont d'abord vérifiées par rapport à l'objet variable pour voir si elles correspondent aux propriétés de ce dernier; s'ils le font, ces propriétés sont utilisées.

Lorsqu'une fermeture survit à la fonction return (ce qui peut se produire pour plusieurs raisons), l'objet variable pour cet appel de fonction est conservé en mémoire par la référence de la fermeture. À première vue, cela suggère que la pile n'est pas utilisée pour les variables locales; en fait, les moteurs JavaScript modernes sont assez intelligents et peuvent (si cela en vaut la peine) utiliser la pile pour les locaux qui ne sont pas réellement utilisés par la fermeture. (Bien entendu, la pile est toujours utilisé pour garder la trace des adresses de retour et autres.)

Voici un exemple:

function foo(a, b) { 
    var c; 

    c = a + b; 

    function bar(d) { 
     alert("d * c = " + (d * c)); 
    } 

    return bar; 
} 

var b = foo(1, 2); 
b(3); // alerts "d * c = 9" 

Lorsque nous appelons foo, un objet variable est créé avec ces propriétés:

  • a et b   — les arguments de la fonction
  • c   — une variable locale déclarée dans la fonction
  • bar   — une fonction déclarée dans la fonction
  • (... et quelques autres)

Lorsque foo exécute l'instruction c = a + b;, il est le référencement les propriétés c, a et b sur l'objet variable pour cet appel à foo. Lorsque foo renvoie une référence à la fonction bar déclarée à l'intérieur, bar survit à l'appel à foo renvoyant. Puisque bar a une référence (cachée) à l'objet variable pour cet appel spécifique à foo, l'objet variable survit (alors que dans le cas normal, il n'aurait aucune référence en suspens et serait donc disponible pour la récupération de place).

Plus tard, quand nous appelons bar, un nouvel objet variables pour cet appel est créé avec (entre autres) une propriété appelée d   — l'argument bar.Les références non qualifiées au sein de bar sont d'abord vérifiées par rapport à l'objet variable pour cet appel; Par exemple, d résout à la propriété d sur l'objet variable pour l'appel à bar. Mais une référence non qualifiée qui ne correspond pas à une propriété sur son objet variable est ensuite vérifiée par rapport à l'objet variable suivant dans la "chaîne de portée" pour bar, qui est l'objet variable pour l'appel à foo. Et puisque cela a une propriété c, c'est la propriété utilisée dans bar. Par exemple, en termes rugueux:

+----------------------------+ 
| `foo` call variable object | 
| -------------------------- | 
| a = 1      | 
| b = 2      | 
| c = 3      | 
| bar = (function)   | 
+----------------------------+ 
      ^
      | chain 
      | 
+----------------------------+ 
| `bar` call variable object | 
| -------------------------- | 
| d = 3      | 
+----------------------------+

Implémentations sont libres d'utiliser le mécanisme qu'ils veulent sous les couvertures pour rendre le ci-dessus semblent arriver. Il est impossible d'obtenir un accès direct à l'objet variable pour un appel de fonction, et la spécification indique clairement que c'est parfaitement bien si l'objet variable est juste un concept, plutôt qu'une partie littérale de l'implémentation. Une implémentation simple peut très bien faire littéralement ce que dit la spécification; un plus compliqué peut utiliser une pile quand il n'y a pas de fermetures impliquées (pour le gain de vitesse), ou peut toujours utiliser une pile mais ensuite "arracher" l'objet variable nécessaire pour une fermeture lors de l'éclatement de la pile. La seule façon de savoir dans un cas spécifique est de regarder leur code. :-)

En savoir plus sur les fermetures, la chaîne de portée, etc. ici:

+0

Merci.Finally compris la fermeture. – Anshul

+0

Qu'est-ce qu'une référence non qualifiée? – LazerSharks

+1

@Gnuey: Le 'foo' dans' foo' mais pas dans 'obj.foo', qui est qualifié avec' obj.'. –

19

la réponse est Unfortunatelly: Cela dépend.

Il y avait un grand changement dans les moteurs JavaScript récents qui ont commencé à optimiser beaucoup mieux que par le passé. La réponse était: "Les variables locales sont stockées dans des trames de pile allouées par tas pour que les fermetures fonctionnent". Ce n'est plus si simple. Il y a eu (ou était il y a 20 ou 30 ans) des recherches sur les implémentations de schémas et l'optimisation des fermetures (JavaScript a hérité à peu près de fermetures de Scheme, sauf pour les suites qui le rendent encore plus compliqué).

Je n'ai pas les liens papier prêts, mais si vous n'avez pas de récupérateur de place incroyablement efficace, vous devez également utiliser la pile. La partie délicate concerne alors les fermetures, qui doivent avoir des variables allouées par tas. Pour cela différentes stratégies sont utilisées.Le résultat est un hybride où:

  • par des fonctions inline, vous pouvez réduire le nombre de trames alloué-tas étant alloué/deallocated considérablement
  • certaines variables peuvent être mis en sécurité sur la pile, car il est temps de vie est limited (il est souvent connecté à la fonction Inline)
  • Dans certains cas, vous savez que vous êtes en train de créer une fermeture, mais vous pouvez attendre jusqu'à ce que cela se produise, puis lui allouer une pile-frame et copier les valeurs actuelles à partir de la pile
  • Il existe des optimisations connectées aux appels de queue, où vous pouvez répartir le tas plus tôt, puis réutiliser. e pile frame pour l'appel de fonction suivante, mais qui n'est pas utilisé dans les moteurs javascript pour autant que je sache actuellement

ce champ change très rapidement dans plusieurs moteurs concurrents, donc la réponse sera probablement toujours "cela dépend En outre, dans les nouvelles versions du langage, nous verrons des fonctionnalités telles que let et const qui facilitent réellement les décisions d'allocation des moteurs. En particulier, l'immuabilité est très utile, car vous pouvez copier des valeurs librement hors de la pile (et faire alors partie de l'objet de fermeture par exemple) sans résoudre les collisions de variables changeantes de différentes fermetures.

+1

Merci beaucoup! Alors, où puis-je apprendre ce genre de choses en plus d'afficher des questions ici? Est-ce en lisant des moteurs à la fine pointe de la technologie (leurs documents et même le code source) ou en cherchant des documents de recherche? Je suis particulièrement intéressé par les stratégies d'optimisation que vous avez mentionnées. Où puis-je trouver des détails à leur sujet? Merci encore! – dacongy

+2

Personnellement, le plus influent pour moi était cette dissertation d'un régime gourou Kent Dybvig http://www.cs.unm.edu/~williams/cs491/three-imp.pdf et il y a quelques documents plus spécialisés/détaillés sur la base de en haut. En outre, j'ai vu récemment beaucoup de choses intéressantes décrivant les moteurs JavaScript actuels et les progrès que les équipes font comme celui-ci http://wingolog.org/archives/2011/07/05/v8-a-tale-of-two -compilers mais ils ne vont généralement pas trop loin. –

+0

le lien d'origine (dans la page d'accueil de l'auteur) est http://www.cs.indiana.edu/~dyb/pubs/3imp.pdf –

Questions connexes