jsМеханизм памяти многих фронтенд-разработчиков не так важен, но если вы хотите узнать большеjs, и эффективно использовать его для создания высококачественных и высокопроизводительных интерфейсных приложений, вы должны понимать механизм памяти js. После понимания механизма памяти, какие основные вопросы, такие как самые основные типы ссылочных данных и передача ссылок? Например, в чем разница между поверхностной копией и глубокой копией? Есть еще замыкания, прототипы и так далее.
тип js
В js типы js делятся на две категории, а именнобазовый тип данныха такжессылочный тип данных. Давайте пока отложим в сторону ES6 и поговорим только о типах в ES5. В ES5 есть 5 простых типов данных (то есть основные типы данных, упомянутые выше): Undefined, Null, Boolean, Number и String. Существует также сложный тип данных Object, который по существу состоит из неупорядоченного набора пар имя-значение. Среди них Array и Function могут быть учтены в объекте.
В памяти примитивные типы данных хранятся в стеке, а ссылочные типы данных — в куче. Говоря об этом, мы должны поговорить о пространстве памяти, Вообще говоря, пространство памяти js делится на стек, кучу и пул (обычно также классифицируется в стеке). В стеке хранятся переменные, в куче — сложные объекты, а в пуле — константы, поэтому его еще называют константным пулом.
Но есть одна переменная, которая является особенной, то есть переменные в замыкании.Переменные в замыкании хранятся не в памяти стека, а в памяти кучи, что объясняет, почему замыкание все еще можно использовать после функции. Ссылка на переменную внутри функции.
function A() {
let a = 1
function B() {
console.log(a)
}
return B
}
Простое определение замыкания: функция A возвращает функцию B, а функция B использует переменные функции A, функция B называется замыканием.
После того, как функция A извлекает стек вызовов, переменные в функции A в это время сохраняются в куче, поэтому функция B все еще может ссылаться на переменные в функции A. Современные JS-движки могут определить, какие переменные нужно хранить в куче, а какие — в стеке, с помощью escape-анализа.
Справочные типы данных и динамическая память
В отличие от других языков, эталонные типы данных JS, такие как массивы, не имеют фиксированного размера. Значения ссылочных типов данных — это объекты, которые хранятся в куче памяти. JavaScript не допускает прямого доступа к местам в куче памяти, поэтому мы не можем напрямую манипулировать пространством кучи памяти объекта. Манипулируя объектом, вы на самом деле манипулируете ссылкой на объект, а не на сам объект. Следовательно, все значения ссылочных типов доступны по ссылке. Ссылку здесь можно приблизительно понимать как адрес, хранящийся в объекте переменных, который связан с фактическим значением памяти кучи.
Чтобы лучше понять переменные объекты и память кучи, мы можем объединить следующие примеры и диаграммы для понимания.
var b = { m: 20 }; // Переменная b хранится в стеке, а соответствующее значение является индексом, указывающим на объект {m: 20}, {m: 20} существует как объект в куче памяти .
Поэтому, когда мы хотим получить доступ к ссылочному типу данных в памяти кучи, по сути, мы сначала получаем ссылку на адрес (или адресный указатель) объекта из объекта-переменной, а затем получаем нужные нам данные из памяти кучи.
Таким образом, возникнет вопрос о ценности, который нам часто задают о ссылочных типах данных.
var x =30;
var b = x;
x+=10;
console.log(b);
Ответить на поставленный выше вопрос легко, ответ заключается в том, что он выведет 30. Операция x не повлияет на b, потому что, когда данные в переменном объекте копируются, система автоматически присваивает новое значение переменной новая переменная. После выполнения var b = a, хотя значения a и b оба равны 20, на самом деле они независимы и не зависят друг от друга. Но интересен следующий вопрос
var x={m:1}
var y = x;
x.m++;
console.log(y.m);
Из вывода мы находим, что ответ равен 2. Это потому, что мы делаем копию ссылочного типа с помощью var y = x. Копирование ссылочного типа также автоматически присваивает новое значение новой переменной и сохраняет его в объекте переменной, но отличие состоит в том, что это новое значение является просто адресным указателем ссылочного типа. Когда указатели адресов одинаковы, хотя они и независимы друг от друга, конкретный объект, к которому осуществляется доступ в переменном объекте, фактически один и тот же.
вывоз мусора
В js есть механизм сборки мусора, и его роль состоит в том, чтобы перерабатывать просроченные и недопустимые переменные для предотвращения утечек памяти. Эти задачи не требуют от нас управления сборкой мусора, js сделает это автоматически, что заставляет нас чувствовать себя очень круто, когда мы пишем код, ха-ха.
Давайте посмотрим, когда механизм сборки мусора js будет перерабатывать переменные. Когда мы пишем код, мы различаем глобальные переменные и локальные переменные.Давайте рассмотрим уничтожение локальных переменных и глобальных переменных.
- локальная переменная: в локальной области видимости, когда функция выполняется, нет необходимости в существовании локальных переменных, поэтому сборщику мусора легко принимать решения и перерабатывать.
- глобальная переменная: сложно определить, когда глобальные переменные должны автоматически освобождать место в памяти, поэтому старайтесь избегать использования глобальных переменных в процессе разработки, чтобы повысить эффективность использования памяти.
Алгоритм сборки мусора
Сегодня основные браузеры используют два метода сборки мусора: удаление меток и подсчет ссылок.
подсчет ссылок
Современные браузеры в основном больше не используются, так что вот краткое введение. Смысл подсчета ссылок заключается в отслеживании количества ссылок на каждое значение. Когда переменная объявляется и ей присваивается ссылочный тип, количество ссылок на это значение равно 1. И наоборот, если переменная, содержащая ссылку на это значение, принимает другое значение, количество ссылок на это значение уменьшается на 1. Когда количество ссылок становится равным 0, это означает, что нет возможности получить доступ к этому значению, поэтому занимаемое им пространство памяти может быть восстановлено. Таким образом, при следующем запуске сборщика мусора он освободит память, занятую значениями, счетчик ссылок которых равен 0. Проще говоря, это посмотреть, есть ли у объекта ссылка на него. Если никакие другие объекты не указывают на него, объект больше не нужен.
// 创建一个对象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 bigBug(){
var objA = new Object();
var objB = new Object();
objA.bug1 = objB;
objB.bug2 = objA;
}
В приведенном выше примере два объекта ab ссылаются друг на друга, то есть их время ссылки всегда равно 2. Если не выполняются никакие другие операции, такие взаимные ссылки вызовут утечку памяти, если они будут использоваться много. Хотя основные браузеры больше не используются, предыдущая версия IE осталась прежней, поэтому мы должны стараться избегать ее при написании кода. Способ избежать этого - вручную развязать петлю, когда она не используется.
objA.bug1 = null;
objB.bug2 = null;
пометить как очищенный
Алгоритм пометки-очистки определяет «неиспользуемые объекты» как «недостижимые объекты». То есть, начиная с корня (глобальный объект в JS), регулярно сканируйте объекты в памяти и сохраняйте все объекты, до которых можно добраться из корня. Объекты, недоступные из корня, помечаются как неиспользуемые и перерабатываются позже. Каждая переменная имеет свою среду использования.После входа в среду механизм сборки мусора пометит ее меткой "вход в среду".По логике вещей система не может очистить переменные в среде,потому что пока она находится в среде среда может использоваться в . Когда он покинет окружающую среду, он будет помечен как «вне окружающей среды» и будет готов к переработке.
утечка памяти
Утечки памяти могут быть незнакомы фронтенд-разработчикам, но вы наверняка сталкивались с явлением зависания браузера, причиной которого может быть полная утечка памяти, вызванная бесконечным циклом. Следовательно, для непрерывно работающего сервисного процесса (демона) память, которая больше не используется, должна вовремя освобождаться. В противном случае использование памяти будет становиться все выше и выше, что повлияет на производительность системы на низком уровне и в худшем случае приведет к сбою процесса. Для памяти, которая больше не используется, если она не освобождается вовремя, это называется утечкой памяти.
Если вы хотите имитировать, вы можете выполнить следующие шаги:
- Откройте инструменты разработчика и выберите Память.
- Проверьте временную шкалу в поле «Выбор типа профилирования» справа.
- Нажмите кнопку записи в левом верхнем углу.
- Выполняйте различные операции на странице, чтобы имитировать использование пользователем.
- По истечении определенного периода времени нажмите кнопку «Стоп» в левом верхнем углу, и на панели отобразится использование памяти за этот период.