Утечка памяти при использовании хвостовой рекурсии - PullRequest
0 голосов
/ 16 июня 2019

Представьте, что у меня есть эта гипотетическая функция (в JavaScript):

function paginationRecursive(results) {
  let intermediate = retrieveNextPage();
  results = results.concat(intermediate)
  if (haveAllResults()) return results;
  return paginationRecursive(results);
}

Будет ли каждое значение intermediate храниться в памяти до тех пор, пока не будет завершена вся рекурсивная обработка, что будет увеличивать использование памяти для каждого рекурсивного вызова каждый раз? Или движок / gc достаточно умен, чтобы освободить эту память в любое время, когда мы делаем один вызов «глубже», потому что он знает, что переменная больше никогда не будет использоваться?

Возможно, это зависит от двигателя (например, V8 , SpiderMonkey , Chakra , и т. Д. ), поэтому сделайте этот вопрос не слишком широким, я предпочитаю знать ответ для двигателя V8.

1 Ответ

1 голос
/ 17 июня 2019

Я думаю, что на данный момент, ответ: «intermediate переменная должна быть освобождена, но она не будет быть».

ES6 говорит о вызовах в хвостовой позиции и даже требует оптимизации:

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

Достойный обзор TCO (оптимизации хвостового вызова) в JS: http://2ality.com/2015/06/tail-call-optimization.html

Все это говорит о том, что страница ссылается на эту таблицу, показывая, что практически никакие среды выполнения на самом деле ее не поддерживают: https://kangax.github.io/compat-table/es6/#test-proper_tail_calls_(tail_call_optimisation)

Эта r/node ветка reddit предлагает некоторое понимание и ссылки на это сообщение в блоге v8 , которое включает в себя:

[...] команда V8 решительно поддерживает обозначение правильных оконечных вызовов специальными синтаксис. Есть ожидающее предложение TC39, названное синтаксическими вызовами чтобы определить это поведение, совместно отстаивали члены комитета из Mozilla и Microsoft. [...] Команда V8 планирует решить вопрос на следующем заседании TC39 перед отправкой подразумевается надлежащим оконечные вызовы или синтаксические оконечные вызовы по умолчанию.

, то есть V8 не хочет реализовывать эту особенность ES6 в соответствии со спецификацией и предпочел бы явный синтаксис для хвостовых вызовов, например , предлагаемый для TC39

См. Также: Оптимизированы ли функции в хвостовом вызове JavaScript?

...