Закрытие утечки памяти неиспользуемых переменных
Я хотел бы понять, при каких обстоятельствах переменные, которые больше не используются, сохраняются в закрытии и приводят к утечкам памяти. Моим самым предпочтительным результатом было бы "нет", но это, похоже, не так.
Из того, что я понимаю, как только функция объявлена внутри другой функции, ее внутренней [[scope]] присваивается LexicalEnvironment своей инкапсулирующей функции. Эта LexicalEnvironment имеет ссылочные локальные переменные и всю цепочку цепей в этой точке. Это в основном включает в себя все свободные переменные, к которым может обращаться функция (из того, что я понял из lostechies, объяснения javascript).
Здесь возникает первый вопрос: это должно означать all, что эти переменные могут быть достигнуты до тех пор, пока функция будет работать. Например. следующее должно уже протекать:
function a() {
let big = new Array(1000000).join('*'); //never accessed
//function unused() { big; }
return () => void 0;
}
let fstore = [];
function doesThisLeak() {
for(let i = 0; i < 100; i++) fstore.push(a());
}
doesThisLeak();
Ответы
Ответ 1
Компилятор может проверить код возвращаемой функции, чтобы увидеть, какие свободные переменные он ссылается, и только эти переменные должны быть сохранены в закрытии, а не всей LexicalEnvironment. Вы можете это увидеть, изучив закрытие в отладчике Javascript.
function a() {
let big = new Array(1000000).join('*');
let small = "abc"; // is accessed
return (x) => small + x;
}
fun = a();
console.dir(fun);
function b() {
let big = "pretend this is a really long string";
function unused() { big; }
return () => void 0;
}
fun = b();
console.dir(fun);
Ответ 2
После вызова a()
ваш fstore
имеет ссылку только на созданную функцию () => void
. После того, как a()
вернется, его рамки будут удалены. Это означает, что никакие вары не имеют ссылки на ваш new Array(1000000).join('*')
, и это будет сбор мусора. Он будет собран таким же образом, если вы раскомментируете функцию unused
, потому что она тоже будет удалена. В вашем коде нет утечек.