Где именно существуют переменные в замыканиях?

JavaScript
Где именно существуют переменные в замыканиях?

Сложность: легко

предисловие

Во время собеседований я часто обсуждаю с кандидатами хранение переменных в замыканиях и обнаружил, что большинство людей останавливаются только на определении замыканий, но неоднозначно относятся к хранению переменных в замыканиях, поэтому в этой статье мы попытаемся пройти. Давайте подробнее рассмотрим анализ 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Получить текущий снимок памяти текущей страницы

image-20201024121621010

Как объяснено здесь, 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:

image-20201024123734636

Ответ кажется очевидным, размер 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), когда она будет израсходована.

image-20201024125719903

Конечно, в реальности может быть не таймер, а в основном пользовательские операции, такие как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/ ах…- хорошо написан