Сложность: легко
предисловие
Во время собеседований я часто обсуждаю с кандидатами хранение переменных в замыканиях и обнаружил, что большинство людей останавливаются только на определении замыканий, но неоднозначно относятся к хранению переменных в замыканиях, поэтому в этой статье мы попытаемся пройти. Давайте подробнее рассмотрим анализ heapdump среды выполнения js-движка.
Пример закрытия
Открываем браузер Chrome и запускаем следующий код:
function makeStevenFunc() {
var stevenx911_name = new Array(1000000).join('x'); //这里通过数组构造一个1MB大小字符串
function displayStevenName() { // 这里定义一个具名函数,方便我们查找
console.log(stevenx911_name);
}
return displayStevenName;
}
var myFunc = makeStevenFunc();
myFunc();
Открытьdevtools
, переключиться наmemory
интерфейс, нажмитеtake heap snapshot
Получить текущий снимок памяти текущей страницы
Как объяснено здесь, heapdump — это моментальный снимок файла памяти кучи.Из приведенных выше результатов мы можем ясно видеть строковую переменную базового типа, определенную в замыканииstevenx911_name
хранится в куче,所以我们可以确认闭包中的变量*会*存在堆(heap)中
.
ноmakeStevenFunc
Все ли определенные переменные войдут в замыкание? Давайте изменим код, чтобы продолжить чтение:
function makeStevenFunc() {
var stevenx911_name = new Array(1000000).join('x');
var stevenx911_desc = new Array(1000000).join('y'); // 增加这句,同样构造一个1MB大小字符串
function displayStevenName() {
console.log(stevenx911_name);
}
return displayStevenName;
}
var myFunc = makeStevenFunc();
myFunc();
Давайте еще раз посмотрим на результаты heapdump:
Ответ кажется очевидным, размер heapdump не изменился,示例代码形成的闭包并没有包含父函数中定义的所有变量
, размещаются только переменные, на которые ссылается подфункция.
На данный момент место хранения переменных в замыкании в основном ясно! Внимательные студенты наверняка обнаружат, что операция heapdump выполняется в конце выполнения приведенного выше кода, но пространство переменных в замыкании не освобождается, и сборщик мусора, похоже, не в состоянии его переработать, так что поговорим о проблемах, вызванных закрытием: Утечка памяти.
Утечки памяти, вызванные замыканиями
В JS закрытие является областью попадания попадания, где утечки памяти, поэтому обязательно будьте осторожны, делайте больше тестов, давайте посмотрим код пример, который вызывает утечки памяти:
var funs = [];
function fun0(){
funs.push(getVar()); //外部变量持有闭包的引用
}
setInterval(fun0, 1000);
function getVar(){
var arr = new Array(1000000);
return function(){
console.log(arr);
}
}
После выполнения этого кода в браузере мы наблюдаемProformance Monitor
можно увидетьJS Heap Size
Он продолжает расти, и объем памяти продолжает увеличиваться, потому что внешняя переменная (глобальная) содержит ссылку на закрытие, и если это происходит на странице, когда использование памяти исчерпано, страница зависает. Решение может заключаться в том, чтобы поместить операцию выделения памяти (новую) вне замыкания или вовремя уничтожить ее (назначить null), когда она будет израсходована.
Конечно, в реальности может быть не таймер, а в основном пользовательские операции, такие какonclick
а такжеonresize
Дождитесь часто вызываемого обратного вызова события.
Суммировать
По поводу хранения переменных в замыкании в интернете было много статей, там много принципиальных схем, и теория тоже очень подробная.Если хотите узнать больше, можете открыть справочную ссылку в справочной части этого статья для углубленного чтения.Кроме того, я думаю, что изучаю js Когда язык:Спецификация ECMAЭто первый авторитет, за ним следует реализация спецификации — движок js, и в-третьих, различные видеоблоги, поэтому эта статья призвана дать всем поверхностное представление о хранении переменных в замыканиях на уровне движка с точки зрения времени выполнения. (над)
Ссылаться на
developer.Mozilla.org/this-cn/docs/…
Developers.Google.com/Web/tools/From…
nuggets.capable/post/684490…- хорошо написан
cloud.Tencent.com/developer/ ах…- хорошо написан