Pile contre tas en Javascript? (La taille maximale de la pile d'appels est dépassée)

j'essaie de construire une page web pour laquelle j'ai besoin d'extraire quelques 100 Mo de données en JavaScript. Avec différents navigateurs, je rencontre des erreurs de "taille maximale de la pile d'appels dépassée" pour différentes quantités de données.

puis-je corriger ce problème en parcourant mon code et en essayant de déplacer les variables locales à l'intérieur des fonctions dans une portée plus globale pour essayer de les affecter sur le tas plutôt que sur la pile? Ou ces concepts n'existent-ils pas dans JavaScript? (Autant que je sache, je n'ai pas avoir n'importe quelles boucles récursives majeures dans mes données, donc c'est vraiment un couple d'énormes chaînes / tableaux de nombres qui semblent causer l'erreur)

Si ce n'est pas possible, est-il possible de demander au navigateur de réserver plus de mémoire?

28
demandé sur Markus A. 2012-06-25 20:35:21

2 réponses

il n'y a pas de séparation de la mémoire en pile/tas en Javascript. Que voyez-vous pourrait être l'une des suivantes:

  1. récursion trop profonde. Dans ce cas, vous aurez besoin de revoir votre algorithme pour le rendre plus itératif et utiliser moins de récursion afin de ne pas frapper pile d'appels limites imposées par les navigateurs.
  2. si votre algorithme n'a pas de recursion profonde, cela pourrait être juste un appel assez profond, considérant que votre code est générer.
  3. enfin, certains moteurs peuvent affecter des arguments de fonction et scoped des variables nommées sur une sorte de pile interne pour une recherche rapide. Si vous (ou le code généré automatiquement) arrive à littéralement utiliser des milliers de variables locales ou des arguments dans la fonction, cela peut déborder les limites spécifiques du moteur ainsi.
16
répondu Oleg V. Volkov 2012-06-26 16:58:33

OK, j'ai trouvé le problème. Il n'y avait vraiment pas de récursion dans mon code. Il est en effet possible d'appeler des fonctions JavaScript avec des centaines d'arguments si ce sont des fonctions "varargs" comme par exemple <array>.splice(...), qui était mon agresseur.

à part: GWT implémente la fonction Java System.arraycopy(...) utiliser la fonction JavaScript splice d'une manière plus ou moins intelligente.

épissure accepte un nombre arbitraire de éléments d'entrée à insérer dans le tableau cible. Il est possible de passer ces éléments d'entrée d'un autre tableau en utilisant la construction suivante:

var arguments = [index, howmany].concat(elements);
Arrays.prototype.splice.apply(targetarray, arguments);

cela équivaut à appeler:

targetarray.splice(index, howmany, elements[0], elements[1], elements[2], ...);

Si augmente (voir ci-dessous pour ce "grand" signifie pour les différents navigateurs), vous obtenir un "Maximum de la pile des appels taille dépassé" erreur sans récursion car le contenu de celui-ci sera chargé sur la pile pour le appel de fonction.

Voici un petit script qui illustre ce problème:

var elements = new Array();
for (i=0; i<126000; i++) elements[i] = 1;
try {
    var arguments = [0, 0].concat(elements);
    Array.prototype.splice.apply(elements, arguments);
    alert("OK");
} catch (err) {
    alert(err.message);
}

en utilisant ce script," big " signifie ce qui suit:

  • Chrome 19: éléments contient environ 125 000 numéros
  • Safari 5.1 (sur Windows): éléments contient ~ 65 000 le nombre
  • Firefox 12: les éléments contient environ 500.000 nombres
  • Opéra 11.61: éléments contient ~ 1 000 000 de numéros

Et le gagnant est: Internet Explorer 8 pour changer! Il peut utiliser toute la mémoire système, avant cet appel de fonction échoue.

a side note: Firefox and Opera lance en fait un message d'erreur différent (plus utile): Function.prototype.s'appliquent: argArray est trop grand

27
répondu Markus A. 2015-05-18 17:09:14