8
votes

La création de fonctions consomme-t-elle plus de mémoire

// Case A
function Constructor() {
  this.foo = function() {
    ...
  };
  ...
}

// vs 
// Case B
function Constructor() {
  ...
};

Constructor.prototype.foo = function() {
  ...
}
One of the main reasons people advise the use of prototypes is that .foo is created once in the case of the prototype where as this.foo is created multiple times when using the other approach.However one would expect interpreters can optimize this. So that there is only one copy of the function foo in case A.Of course you would still have a unique scope context for each object because of closures but that has less overhead then a new function for each object.Do modern JS interpreters optimise Case A so there is only one copy of the function foo ?

0 commentaires

3 Réponses :


10
votes

Oui, la création de fonctions utilise plus de mémoire.

... et, non, les interprètes ne optimisent pas la case une seule fonction. P>

La raison est La chaîne de la scorie JS nécessite chaque instance d'une fonction pour capturer les variables disponibles au moment de sa création. Cela dit, Les interprètes modernes sont Meilleur à propos de ce cas, mais en grande partie parce que la performance des fonctions de fermeture était un problème connu il y a quelques années. P >

Mozilla dit à Évitez les fermetures inutiles pour cette raison, Mais les fermetures sont l'un des outils les plus puissants et les plus utilisés dans une boîte à outils de JS Developer. P>

Mise à jour: strong> il suffit de courir Ce test qui crée 1 million d'instances de constructeur, à l'aide de nœud.js (qui est v8, l'interprète JS en chrome). Avec casea = true code> i Obtenir cette utilisation de la mémoire: p> xxx pré>

et avec casea = false code> Je reçois cette utilisation de la mémoire: P>

{
    rss: 73535488,       //73 MB
    vsize: 3149352960,   //3149 MB
    heapTotal: 74908960, //74 MB
    heapUsed: 56308008   //56 MB
}


4 commentaires

Pouvons-nous avoir des références qui définissent "mieux" et "interprètes modernes"


Vos tests correspondent à ce que j'ai trouvé dans la mienne aussi --- J'ai également ajouté des blocs de code volumineux à l'intérieur de la fonction pour tester si cela rendait le ballon de mémoire tout plus rapidement - et il n'a pas ... le code à l'intérieur de la fonction ne prend pas mémoire supplémentaire.


Oh - et j'ai également déconnecté une utilisation de la mémoire avant et après le test pour mesurer le diffusté avant la création d'objets


Peut-être la peine d'être vérifiée contre le chrome Canary V32 - on dirait qu'il y a eu des améliorations.



0
votes

Les interprètes JavaScript ne sont pas l'optimisation des objets prototypes non plus. C'est simplement un cas de là en l'étant l'un d'entre eux par type (cette référence de plusieurs instances). Des constructeurs, d'autre part, créent de nouvelles instances et les méthodes définies dans elles. Donc, par définition, ce n'est vraiment pas un problème de «optimisation» d'interprétation, mais de simplement comprendre ce qui se passe.

sur une note latérale, si l'interprète devait essayer de consolider des méthodes d'instance, vous rencontreriez des problèmes si vous avez déjà décidé de modifier la valeur d'une dans une instance particulière (je préférerais que les maux de tête ne soient pas ajoutés à la langue) :)


3 commentaires

Le compilateur optimise la fonction, elle n'oblige pas cependant le scopecontext.


Comment chaque interprète gère les doublons ne semble pas vraiment être la question cependant, l'interprète devra établir une différence entre plusieurs méthodes d'instance et cette différence consommera plus de mémoire.


Pour un cas, je m'attendrais à ce que un compilateur voit qu'il n'y a pas de variables locales dans le constructeur, il n'est donc pas nécessaire de garder son objet variable sur la chaîne d'étendue des instances. Si des variables locales sont utilisées, elle ne peut pas le faire, sauf si elle est suffisamment intelligente d'optimiser l'objet de variable si la fonction interne ne les réfère pas. Quoi qu'il en soit, j'utiliserais l'approche prototype comme son nitre et plus facilement maintenu (IMO bien sûr).



2
votes

Je crois, après un bref test de noeud, que, dans les deux cas A et B, une copie du code réel pour la fonction foo en mémoire.

Case A - Il existe un objet de fonction créé pour chaque exécution du constructeur stockant une référence au code de fonctions et son champ d'exécution actuel.

Case B - Il n'y a qu'une seule portée, un objet de fonction, partagé via un prototype.


2 commentaires

Pouvez-vous poster votre code de test? Je suis sûr qu'il y a une certaine optimisation à l'intérieur de l'interprète pour éviter que analyse le code de fonction chaque fois, mais chaque passage à travers le constructeur doit capturer des références à toutes les variables en périmètre afin qu'elles puissent être correctement. résolu lorsque la fonction est invoquée.


@Broofa - Comparer mon code à la vôtre, c'est fondamentalement le même ... :) - Je viens de larguer comme 40 lignes de code de quelque chose d'autre dans la fonction pour tester cela ...