Обмеження розміру стека для браузера Javascript


75

Я отримую деякі проблеми з переповненням стеку Javascript на стороні клієнта, особливо в браузері IE, це відбувається всередині сторонньої бібліотеки, яка здійснює деякі виклики функцій, і з якихось причин вони іноді гальмують в IE лише через низький ліміт стеку.

Потім я закодував невеликий тестовий HTML, щоб перевірити обмеження розміру стека для деяких браузерів і виявив, що IE8 насправді має невеликий ліміт стека в порівнянні з FF 7 або Chrome 14, що працюють на ноутбуці з ОС Windows 7, 8 Гб оперативної пам'яті:

<html>
<body>

<!-- begin Script: -->
<script type="text/javascript">

function doSomething(){

  var i = 3200;
  doSomethingElse(i);

}

function doSomethingElse(i){
  if (i == 0) return -1;
  doSomethingElse(i-1);
}

doSomething(); 

</script>
<!-- END OF PAGE -->

</body>
</html>

IE піднімає переповнення стека, коли значення складають близько 3200, Firefox і Chrome можуть обробляти дуже глибоку рекурсію в порівнянні з IE.

Я хотів би знати, чи є спосіб пов’язати виняток із переповнення стека з функцією Javascript, яка підняла його під час виконання в IE або будь-якому іншому браузері, і чи може вона дати стек-трас із ланцюжком функцій у стеку на момент, коли помилка була піднята.


2
3200 дзвінків - це достатньо місця для стека. Програмісти на Python (ну, ті, хто не прагне писати парсери рекурсивного спуску або замінювати абсолютно прості цикли рекурсією), чудово ладнають з обмеженням на 1000 викликів. Що ви робите?

4
У запитальному режимі це не сформульовано жахливо, але останнє речення "Цікаво, чи є ..." можна почати з "Чи є" і закінчити знаком питання, даючи досить пряме запитання.
jball

Дякую за відгук, я чіткіше роз'ясню питання
Gilhebl

Відповіді:


129

За допомогою простого тесту:

var i = 0;
function inc() {
  i++;
  inc();
}
    
try {
  inc();
}
catch(e) {
  console.log('Maximum stack size is', i, 'in your current browser');
}

Internet Explorer

  • IE6: 1130
  • IE7: 2553
  • IE8: 1475
  • IE9: 20678
  • IE10: 20677

Mozilla Firefox

  • 3,6: 3000
  • 4,0: 9015
  • 5,0: 9015
  • 6,0: 9015
  • 7,0: 65533
  • 8b3: 63485
  • 17: 50762
  • 18: 52596
  • 19: 52458
  • 42: 281810

Гугл хром

  • 14: 26177
  • 15: 26168
  • 16: 26166
  • 25: 25090
  • 47: 20878
  • 51: 41753

Сафарі

  • 4: 52426
  • 5: 65534
  • 9: 63444

Опера

  • 10.10: 9999
  • 10.62: 32631
  • 11: 32631
  • 12: 32631

Край

  • 87: 13970

Що стосується вашого запитання, скористайтеся інструментами розробника вашого браузера, щоб побачити стек. В IE 8+ натисніть F12, перейдіть на вкладку Сценарій і натисніть кнопку Почати налагодження. Він порушиться, коли буде видано виняток, і ви побачите стек викликів. Ви також можете використовувати інструменти розробника Chrome Ctrl+ Shift+ J.


7
Ви також можете використовувати F12 для Chrome
Хуан Мендес,

1
За допомогою тесту jsfiddle.net/9YMDF/show я отримав ~ 21000 для Chrome 28, 26000..53000 для Firefox 20+ та ~ 3000 для IE10 у Windows 7 SP1 64-bit. У Opera 12.X глибина стека майже близька до 32768. І я знайшов одну нещасну установку IE8 з глибиною стека, рівною 276!
Віктор

Ви можете порівняти ці результати з BrowserScope, зв’язаним тут
Janus Troelsen

Це дає мені 151102 на Microsoft Edge, тоді як на IE11 його 54375!
Gaurav Ojha

5
Я думаю , що цифри не відображаються в браузері, але в пам'яті в даний час зарезервовано додатком. через це відповіді дуже різняться. Для exampl, e я щойно провів цей тест, і я отримую 20922 для Chrome 56 (з великою кількістю розширень) і 8921 для досить простого ванільного Firefox 49. З абсолютно запасним браузером я отримую 16615.
Роберто Томас,

7

Це стосується браузера, не тільки розміру стека, але й оптимізацій, таких як оптимізація рекурсії хвоста та інше. Думаю, єдиною надійною річчю тут є кодування таким чином, щоб не вкладати тонни речей у стек, або тестування кожного браузера вручну (глибоке читання документації). Зрештою, коли ви бачите помилку "занадто багато рекурсії" або подібну, ви вже знаєте, що з вашим кодом щось насправді не так.


чи справді TCO виконується в JavaScript? Я читав, що ES6 може отримати підтримку, але я не думаю, що вона ще впроваджена.
Janus Troelsen

Зараз TCO стоїть за прапором у chrome (оцінюються дві різні реалізації). Мені невідомо про жоден браузер, який реалізував би це за замовчуванням.
Джетро Ларсон,

1
@JanusTroelsen: ES2015 ("ES6") справді вимагає, щоб двигуни виконували TCO. У V8 він є, але команда V8 ще не вважає його "стабільним", тому вам доведеться його ввімкнути. (V8 класифікує всі запущені ними функції як "доставку" [виконано], "стабільно" і "виконується". TCO залишається "в процесі", але основи є для всіх трьох генераторів коду V8. Я думаю, що вони ще не підвищив його до "стабільного", оскільки вони все ще оптимізують / пошук помилок / виправлення помилок. Докладніше тут: stackoverflow.com/a/30369729/157247 )
TJ Crowder,

В даний час сафарі - це лише браузер із належним TCO
ridderhoff

Одним із варіантів використання "покласти тонни речей на стек" є array1.push(...array2)набагато швидший, ніж, array1 = array1.concat(array2)але викидає "максимальний розмір стека перевищений", коли масив2 занадто довгий. дивись тут
Міла Наутікус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.