[Расширенная фаза 1–4] Подробное изучение JavaScript поможет вам разобраться в механизме памяти.

внешний интерфейс алгоритм JavaScript

Обновление: Спасибо за вашу поддержку. Недавно я бросил сводку данных для всех, чтобы прочитать систему. В будущем будет больше контента и больше оптимизации.Нажмите здесь, чтобы просмотреть

------ Далее идет текст ------

Тема этого выпускастек вызовов, план имеет в общей сложности 28 фаз,Каждый выпуск фокусируется на преодолении трудности собеседования, если вы не знаете этот расширенный план, нажмите, чтобы просмотреть все статьи в конце статьи.

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


Пространство памяти JS разделено накуча,куча,Пул (обычно также классифицируется как стек). вкучахранить переменные,кучахранить сложные объекты,бассейнХраните константы, поэтому его еще называют константным пулом.

Во вчерашней статье были представлены кучи и стеки. Подводя итог:

  • Основной тип: -->память (исключая переменные в замыканиях)
  • Тип ссылки: -->ОЗУ

Дополнение сегодняСуть в том, что переменные в замыкании не хранятся в памяти стека, а хранятся в堆内存, что объясняет, почему замыкание может ссылаться на переменные в функции после самой функции.

function A() {
  let a = 1
  function B() {
      console.log(a)
  }
  return B
}

闭包Простое определение: функция A возвращает функцию B, а функция B использует переменные функции A, функция B называется замыканием.

После того, как функция A извлекает стек вызовов, переменные в функции A в это время сохраняются в куче, поэтому функция B все еще может ссылаться на переменные в функции A. Современные JS-движки могут определить, какие переменные нужно хранить в куче, а какие — в стеке, с помощью escape-анализа.

Внедрение замыканий до сих пор,[Расширенная фаза 2] Закрытие областиОн будет представлен подробно, так что следите за обновлениями.

В центре внимания сегодняшней статьивосстановление памятиа такжеутечка памяти.

восстановление памяти

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

  • Уничтожение локальных и глобальных переменных
    • локальная переменная: в локальной области видимости, когда функция выполняется, нет необходимости в существовании локальных переменных, поэтому сборщику мусора легко принимать решения и перерабатывать.
    • глобальная переменная: сложно судить, когда глобальные переменные должны автоматически освобождать место в памяти, поэтому постарайтесь разработатьизбегатьИспользуйте глобальные переменные.
  • Взяв в качестве примера движок Google V8, все объекты JS в движке V8 передаются черезкучадля выделения памяти
    • первоначальное распределение: Когда переменная объявлена ​​и назначена, движок V8 выделит эту переменную в куче памяти.
    • продолжать применять: когда запрашиваемой памяти недостаточно для хранения этой переменной, механизм V8 будет продолжать запрашивать память до тех пор, пока размер кучи не достигнет верхнего предела памяти механизма V8.
  • Движок V8 выполняет объекты JS в куче памятиУправление генерацией
    • Кайнозой: объекты JS с коротким жизненным циклом, такие как временные переменные, строки и т. д.
    • старое поколение: Объекты, которые все еще выживают после нескольких сборок мусора и имеют длительный жизненный цикл, например главный контроллер, серверные объекты и т. д.

Алгоритм сборки мусора

Для алгоритма сборки мусора основная идея заключается в том, как определить, что память больше не используется.Существуют следующие два широко используемых алгоритма сборки мусора.

  • Подсчет ссылок (больше не используется современными браузерами)
  • Прозрачная маркировка (общая)
подсчет ссылок

Алгоритм подсчета ссылок определяет критерий «память больше не используется» очень просто, чтобы увидеть, есть ли у объекта указатель на него.Цитировать. Если никакие другие объекты не указывают на него, объект больше не нужен.

// 创建一个对象person,他有两个指向属性age和name的引用
var person = {
    age: 12,
    name: 'aaaa'
};

person.name = null; // 虽然name设置为null,但因为person对象还有指向name的引用,因此name不会回收

var p = person; 
person = 1;         //原来的person对象被赋值为1,但因为有新引用p指向原person对象,因此它不会被回收

p = null;           //原person对象已经没有引用,很快会被回收

У подсчета ссылок есть фатальная проблема, и этоциклическая ссылка

Если два объекта ссылаются друг на друга, даже если они больше не используются, сборщик мусора не будет их собирать, что в итоге может привести к утечке памяти.

function cycle() {
    var o1 = {};
    var o2 = {};
    o1.a = o2;
    o2.a = o1; 

    return "cycle reference!"
}

cycle();

cycleПосле выполнения функции объектo1а такжеo2На самом деле он уже не нужен, но по принципу подсчета ссылок взаимная ссылка между ними все равно существует, так что эта часть памяти не будет рекультивирована. Итак, современные браузерыБольше не использоватьэтот алгоритм.

Но IE по-прежнему использует его.

var div = document.createElement("div");
div.onclick = function() {
    console.log("click");
};

Приведенное выше очень распространено, но приведенный выше пример является циклической ссылкой.

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

Пометить как очищенный (общий)

Алгоритм маркировки-очистки определяет «объекты, которые больше не используются» как «недоступный объектТо есть, начиная с корня (глобальный объект в JS), регулярно сканируются объекты в памяти. Любой объект, до которого можно добраться из корня,резерв. Объекты, недоступные из корня, помечаются какБольше не использовать, чтобы быть переработаны позже.

Недостижимые объекты включают в себя концепцию объектов без ссылок, но не обязательно наоборот.

Таким образом, приведенный выше пример может быть правильно собран мусором.

Так что теперь для основных браузеров необходимо только отрезать связь между объектом, который нужно переработать, и корнем. Наиболее распространенные утечки памяти обычно связаны с привязками элементов DOM:

email.message = document.createElement(“div”);
displayList.appendChild(email.message);

// 稍后从displayList中清除DOM元素
displayList.removeAllChildren();

В приведенном выше кодеdivЭлемент был удален из дерева DOM, ноdivЭлемент также привязан к объекту электронной почты, поэтому, если объект электронной почты существует,divЭлементы всегда сохраняются в памяти.

утечка памяти

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

Метод выявления утечки памяти

1. Браузерный метод
  1. Откройте инструменты разработчика и выберите Память.
  2. Проверьте временную шкалу в поле «Выбор типа профилирования» справа.
  3. Нажмите кнопку записи в левом верхнем углу.
  4. Выполняйте различные операции на странице, чтобы имитировать использование пользователем.
  5. По истечении определенного периода времени нажмите кнопку «Стоп» в левом верхнем углу, и на панели отобразится использование памяти за этот период.
2, метод командной строки

использоватьNodeкоторый предоставилprocess.memoryUsageметод.

console.log(process.memoryUsage());

// 输出
{ 
  rss: 27709440,		// resident set size,所有内存占用,包括指令区和堆栈
  heapTotal: 5685248,   // "堆"占用的内存,包括用到的和没用到的
  heapUsed: 3449392,	// 用到的堆的部分
  external: 8772 		// V8 引擎内部的 C++ 对象占用的内存
}

Чтобы определить утечку памяти,heapUsedполе должно превалировать.

Подробный анализ памяти JS будет выполнен в[Расширенная фаза 20] Оптимизация производительностиПожалуйста, с нетерпением ждите подробного введения.

WeakMap

В ES6 есть две новые структуры данных:WeakSetа такжеWeakMap, указывая на то, что это слабая ссылка, и их ссылки на значения не включаются в механизм сборки мусора.

const wm = new WeakMap();
const element = document.getElementById('example');

wm.set(element, 'some information');
wm.get(element) // "some information"

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

Ответы на вчерашние мыслительные вопросы

Вчерашняя статья оставила вопрос-мысль.Обсуждение в группе было очень оживленным.Принцип должен знать каждый.Теперь кратко ответим на него.

var a = {n: 1};
var b = a;
a.x = a = {n: 2};

a.x 	// --> undefined
b.x 	// --> {n: 2}

Ответ был написан выше, ключ к этому вопросу

  • 1. Приоритет..приоритет выше, чем=, поэтому сначала выполнитеa.x, в куче памяти{n: 1}станет{n: 1, x: undefined}, после изменения соответствующегоb.xТакже изменился, потому что он указывает на тот же объект.
  • 2. Операция присваивания从右到左, поэтому сначала выполнитеa = {n: 2},aСсылка изменяется, и возвращаемое значение присваиваетсяa.x,требует вниманияэтот разa.xэто первый шаг{n: 1, x: undefined}Этот объект на самом делеb.x, эквивалентноb.x = {n: 2}

Сегодняшние вопросы для размышлений

Вопрос первый:

В чем существенная разница между null и undefined с точки зрения памяти?

Вопрос второй:

const в синтаксисе ES6 объявляет константу только для чтения, так почему же значение const может быть изменено ниже?

const foo = {}; 
foo = {}; // TypeError: "foo" is read-only
foo.prop = 123;
foo.prop // 123

Вопрос третий:

При каких обстоятельствах возможны утечки памяти?

Ссылаться на

Механизм памяти JavaScript

Приоритет оператора MDN

Изучение JavaScript по спецификациям ES (2): глубокое понимание проблемы «непрерывного присваивания».

InterviewMap