TGViewer
melikhov.dev melikhov.dev @melikhov_dev · 4.73K subscribers
Post #232 6.86K
Студент прислал вопрос — почему этот код тормозит?


console.time ("answer time");
const max = 100000000000;

console.log(' max=', max);
let i = 0;
while(i < max) {
const y = Math.pow(2,100);
const z = Math.pow(15, 100000);
i++;
}
console.timeEnd("answer time");


Вот эта штука крутится почти две минуты. И даже убрать тело цикла в функцию, чтобы гарантированно попасть в кэши JIT никак не помогает. Неужели JIT настолько плох, что не может оптимизировать бесполезные вызовы?

Что же, открываем Deopt Explorer и ищем проблему. На самом деле, вот этот код будет тормозить точно так же:


const max = 100000000000;

let i = 0;
while(i < max) {
i++;
}


Deopt Explorer сразу даёт нам причину деоптимизации —
i++ (overflow)
. Что за дела, спросите вы? Это же далеко не Number.MAX_SAFE_INTEGER, запаса достаточно. Дело в том, что V8 (как и другие JS-движки) умеет эффективно работать со SMI (small integers). На 64-битных платформах это соответственно диапазон от -2³¹ до 2³¹-1.

Проверим?


%DebugPrint(2147483647);

DebugPrint: Smi: 0x7fffffff (2147483647)


А вот мы вышли за границы SMI:


%DebugPrint(2147483648);

DebugPrint: 2147483648.0
0x148993d415e9: [Map] in ReadOnlySpace
- type: HEAP_NUMBER_TYPE
- instance size: 16
- elements kind: HOLEY_ELEMENTS
- unused property fields: 0
- enum length: invalid
- stable_map
- back pointer: 0x148993d415b9 <undefined>
- prototype_validity cell: 0
- instance descriptors (own) #0: 0x148993d41269 <Other heap object (STRONG_DESCRIPTOR_ARRAY_TYPE)>
- prototype: 0x148993d41339 <null>
- constructor: 0x148993d41339 <null>
- dependent code: 0x148993d41251 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
- construction counter: 0


Такой подход называется pointer tagging — за счёт отдельного бита мы можем точно сказать, что в данном случае у нас не указатель на heap, а непосредственно значение примитива. Т.е. брать значение прямо из стека, а не бегать за ним в кучу. Получается, что как только мы выходим за границу SMI мы уже начинаем работать с объектом в куче и теряем в производительности.

В итоге как обычно попали в ловушку синтетических тестов и протестировали не то, что хотели протестировать, но многое поняли :)

UPD

Бенчмарки для оригинального цикла: 1:35.161 (m:ss.mmm)

Для решения с вложенным циклом (чтобы указатели остались в smi): 48.156s

А если мы поможем JIT и вложенный цикл уберём в функцию, то: 32.325s
  • 🔥 58
  • ❤ 19
  • 🤯 8
  • 👍 6
  • ❤‍🔥 1
More from @melikhov_dev
  1. Sep 26, 2026Блин, ну нравятся мне TUI решения, сил нет. Просто, красиво и понятно (для меня). Продолжа…
  2. Sep 13, 2026Какой он — личный харнес? Вот мы и пришли в точку, когда уже бизнес не устраивает медленна…
  3. Aug 30, 2026Разобрал своего питонячего новостного бота и собрал нового, уже на Гермесе. Ну как собрал…
  4. Aug 24, 2026Вы могли наверное заметить что как-то мало меня стало в последнее время. Не видно на конфе…
  5. Aug 6, 2026Как же хорошо перечитывается сейчас «Трилогия Муравейника» Гибсона (она же Sprawl trilogy)…
  6. Aug 1, 2026github показал очередную полезную штуку — Stacked pull requests. Даже жалко, что как обычн…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →