Сборка мусора — это скрытый механизм JavaScript
. Обычно нам не нужно беспокоиться о сборке мусора, нам нужно только сосредоточиться на разработке функций. Но это не значит, что мы можем сидеть сложа руки и расслабляться при написании JavaScript
. По мере того, как реализуемые нами функции становятся все более сложными, а объем кода накапливается, проблемы с производительностью становятся все более заметными. Как написать код, который выполняется быстрее и занимает меньше памяти, — это бесконечная задача программистов. Отличный программист всегда может добиться потрясающих результатов при крайне ограниченных ресурсах. В этом и заключается разница между обычными существами и отстраненными богами.
код? При выполнении в памяти компьютера все переменные, объекты и функции, которые мы определяем в коде, занимают определенный объем памяти. В компьютерах объем памяти — очень ограниченный ресурс. Мы всегда должны обращать внимание на использование памяти. В конце концов, модули памяти очень дороги! Переменную, функцию или объект можно назвать мусором, если после создания они больше не нужны для последующего выполнения кода.
Хотя интуитивно понять определение мусора очень легко, для компьютерной программы нам трудно в определенный момент сделать вывод, что существующие в настоящее время переменные, функции или объекты больше не будут использоваться в будущем. Чтобы снизить затраты компьютерной памяти и обеспечить нормальное выполнение компьютерных программ, мы обычно оговариваем, что объекты или переменные, удовлетворяющие любому из следующих условий, являются мусором:
переменные или объекты, на которые нет ссылок, эквивалентны дому без двери. Мы никогда не сможем войти в него, поэтому их невозможно использовать. Хотя недоступные объекты и соединяются, они все равно недоступны снаружи и поэтому не могут быть использованы повторно. Объекты или переменные, соответствующие вышеуказанным условиям, никогда больше не будут использоваться при дальнейшем выполнении программы, поэтому их можно смело рассматривать как сборку мусора.
Когда мы уточняем объекты, которые необходимо отбросить, посредством приведенного выше определения, означает ли это, что в остальных переменных и объектах мусора нет?
Нет! Мусор, который мы сейчас идентифицируем, — это лишь часть всего мусора. Еще будет оставаться другой мусор, не соответствующий вышеуказанным условиям, но он не будет использоваться повторно.
Можно ли сказать, что мусор, соответствующий приведенному выше определению, является «абсолютным мусором», а другой мусор, скрытый в программе, — «относительным мусором»?
Механизм сборки мусора ( GC,Garbage Collection
) отвечает за переработку ненужных переменных и пространства памяти, занимаемого во время выполнения программы. Явление, когда объект все еще существует в памяти, даже если у него нет возможности быть использованным снова, называется утечкой памяти . Утечки памяти — очень опасное явление, особенно в долго выполняющихся программах. Если в программе есть утечка памяти, она будет занимать все больше и больше места в памяти, пока не закончится память.
Строки, объекты и массивы не имеют фиксированного размера, поэтому динамическое выделение памяти для них можно выполнить только в том случае, если известен их размер. Каждый раз, когда программа JavaScript создает строку, массив или объект, интерпретатор выделяет память для хранения объекта. Всякий раз, когда память распределяется таким образом динамически, в конечном итоге она должна быть освобождена, чтобы ее можно было использовать снова; в противном случае интерпретатор JavaScript будет использовать всю доступную память в системе, что приведет к сбою системы.
Механизм сборки мусора JavaScript
будет периодически проверять наличие бесполезных переменных и объектов (мусора) и освобождать занимаемое ими пространство.
В разных языках программирования используются разные стратегии сборки мусора. Например, C++
нет механизма сбора мусора. Все управление памятью зависит от собственных навыков программиста, что затрудняет освоение C++
. JavaScript
для управления памятью используется достижимость . Это означает, что программа может каким-либо образом получать доступ к переменным и объектам и использовать их. Память, занятая этими переменными, не может быть освобождена.
JavaScript
определяет внутренний набор достижимых значений, а значения в этом наборе являются достижимыми по своей сути:
называются корнями и являются верхними узлами дерева достижимости;
Переменная или объект считается достижимой, если она прямо или косвенно используется корневой переменной.
Другими словами, значение достижимо, если оно может быть достигнуто через корень (например, Abcde
).
пусть люди = { мальчики:{ мальчики1:{имя:'сяомин'}, мальчики2:{name:'xiaojun'}, }, девушки:{ девочки1: {name: 'сяохун'}, Girls2:{name:'huahua'}, }};
Приведенный выше код создает объект и присваивает его переменной people
. Переменная people
содержит два объекта, boys
и girls
, а boys
и girls
содержат два подобъекта соответственно. При этом также создается структура данных, содержащая 3
уровня ссылочных отношений (независимо от данных базового типа), как показано ниже:
Среди них узел people
естественно доступен, поскольку это глобальная переменная. Узлы boys
и girls
доступны косвенно, поскольку на них напрямую ссылаются глобальные переменные. boys1
, boys2
, girls1
и girls2
также являются доступными переменными, поскольку они косвенно используются глобальными переменными и доступны через people.boys.boys
.
Если мы добавим следующий код после приведенного выше кода:
people.girls.girls2 = null;people.girls.girls1 =people.boys.boys2
Тогда приведенная выше диаграмма справочной иерархии примет следующий вид:
Среди них узлы girls1
и girls2
стали недоступными из-за отключения от узла grils
, а значит, будут переработаны механизмом сбора мусора.
И если в это время мы выполним следующий код:
people.boys.boys2 = null,
то диаграмма ссылочной иерархии примет следующий вид:
В настоящее время, хотя узлы boys
и boys2
отключены, из-за ссылочной связи между узлами boys2
и girls
узла boys2
по-прежнему доступен и не будет переработан механизмом сборки мусора.
Приведенная выше диаграмма ассоциаций доказывает, почему эквивалентное значение глобальной переменной называется корнем , поскольку на диаграмме ассоциаций этот тип значения обычно отображается как корневой узел дерева отношений.
пусть люди = { мальчики:{ мальчики1:{имя:'сяомин'}, мальчики2:{name:'xiaojun'}, }, девушки:{ девочки1: {name: 'сяохун'}, Girls2:{name:'huahua'}, }};people.boys.boys2.girlfriend =people.girls.girls1; //boys2 относится к Girls1people.girls.girls1.boyfriend =people.boys.boys2; //girls1 относится к Boys2.
Приведенный выше код создает взаимосвязанные отношения между boys2
и girls1
. Схема структуры отношений выглядит следующим образом:
На этом этапе, если мы отключим связь между boys
и boys2
:
удалим люди.мальчики.мальчики2,
диаграмма связи между объектами будет следующей:
Очевидно, что недостижимых узлов не существует.
На этом этапе, если мы прервём связь boyfriend
:
удалимpeople.girls.girls1,
диаграмма отношений примет вид:
В это время, хотя между boys2
и girls1
все еще существуют отношения girlfriend
, boys2
становится недоступным узлом и будет очищен механизмом сборки мусора.
пусть люди = { мальчики:{ мальчики1:{имя:'сяомин'}, мальчики2:{name:'xiaojun'}, }, девушки:{ девочки1: {name: 'сяохун'}, Girls2:{name:'huahua'}, }};deletepeople.boys;deletepeople.girls
Диаграмма ссылочной иерархии, сформированная приведенным выше кодом, выглядит следующим образом:
В настоящее время, хотя между объектами внутри пунктирного прямоугольника все еще существуют отношения взаимных ссылок, эти объекты также недоступны и будут удалены механизмом сборки мусора. Эти узлы потеряли связь с корнем и стали недоступными.
Так называемый подсчет ссылок, как следует из названия, подсчитывает каждый раз, когда на объект ссылаются. Добавление ссылки увеличит ее на единицу, а удаление ссылки уменьшит ее на единицу. число становится равным 0, оно считается мусором, поэтому объекты удаляются для освобождения памяти.
Например:
let user = {username:'xiaoming'}; //На объект ссылается пользовательская переменная count +1 пусть пользователь2 = пользователь; //На объект ссылается новая переменная, а счетчик +1 пользователь = ноль; //Переменная больше не ссылается на объект, счетчик равен -1 пользователь2 = ноль; //Переменная больше не ссылается на объект, нечетное число -1 //В данный момент количество ссылок на объекты равно 0 и будут удалены.
Хотя метод подсчета ссылок кажется очень разумным, на самом деле в механизме повторного использования памяти, использующем метод подсчета ссылок, есть очевидные лазейки.
Например:
пусть мальчик = {}; пусть девушка = {}; мальчик.подруга = девочка; девушка.бойфренд = мальчик; мальчик = ноль; Girl = null;
В приведенном выше коде есть взаимные ссылки между boy
и girl
. Подсчет удаляет ссылки в boy
и girl
, и эти два объекта не будут переработаны. Из-за существования циклических ссылок счетчики ссылок двух анонимных объектов никогда не вернутся к нулю, что приведет к утечке памяти.
В C++
существует концепция интеллектуального указателя ( shared_ptr
). Программисты могут использовать интеллектуальный указатель для использования деструктора объекта для освобождения счетчика ссылок. Однако в случае циклических ссылок будут происходить утечки памяти.
К счастью, JavaScript
принята другая, более безопасная стратегия, которая в большей степени позволяет избежать риска утечек памяти.
Маркировка mark and sweep
— это алгоритм сбора мусора, принятый движком JavaScript
. Его основной принцип — начать с корня , пройти в ширину ссылочные отношения между переменными и поставить отметку (优秀员工徽章
) на пройденных переменных. Неотмеченные объекты окончательно удаляются.
Основной процесс алгоритма следующий:
2
до тех пор, пока не будет присоединено новых отличников;Например:
если в нашей программе есть связь со ссылкой на объект, как показано ниже:
Мы ясно видим, что в правой части всего изображения есть «достижимый остров». Начиная с корня , до острова невозможно добраться. Но у сборщика мусора нет такого божьего взгляда, как у нас. Они только пометят корневой узел как выдающегося сотрудника на основании алгоритма.
Затем начните с выдающихся сотрудников и найдите все узлы, упомянутые выдающимися сотрудниками, например три узла в пунктирной рамке на рисунке выше. Затем отметьте вновь найденные узлы как выдающихся сотрудников.
Процесс поиска и маркировки повторяется до тех пор, пока все узлы, которые удастся найти, не будут успешно помечены.
Наконец, достигается эффект, показанный на рисунке ниже:
Поскольку острова справа по-прежнему не отмечены после завершения цикла выполнения алгоритма, эти узлы не смогут быть доступны для задачи сборщика мусора и в конечном итоге будут очищены.
Дети, изучавшие структуры данных и алгоритмы, могут быть удивлены, обнаружив, что это обход графа, аналогичный алгоритмам связных графов.
Сбор мусора — масштабная задача. Особенно когда объем кода очень велик, частое выполнение алгоритма сборки мусора существенно замедлит выполнение программы. Алгоритм JavaScript
внес множество оптимизаций в сборку мусора, чтобы гарантировать эффективное выполнение программы, обеспечивая при этом нормальное выполнение работ по переработке.
Стратегии, принятые для оптимизации производительности, обычно включают следующие моменты:
Программы JavaScriptJavaScript
поддерживать значительное количество переменных во время выполнения, и частое сканирование этих переменных приведет к значительным накладным расходам. Однако эти переменные имеют свои особенности в жизненном цикле. Например, локальные переменные часто создаются, быстро используются, а затем отбрасываются, тогда как глобальные переменные занимают память в течение длительного времени. JavaScript
управляет двумя типами объектов отдельно. Сборщик мусора часто сканирует локальные переменные, которые быстро создаются, используются и удаляются, чтобы обеспечить быструю очистку этих переменных после того, как они перестанут использоваться. Для переменных, которые занимают память в течение длительного времени, уменьшите частоту их проверки, тем самым сэкономив определенное количество накладных расходов.
Идея инкрементальной сборки очень распространена при оптимизации производительности, а также может использоваться для сборки мусора. Когда количество переменных очень велико, очевидно, что одновременный просмотр всех переменных и выставление выдающихся оценок сотрудникам занимает очень много времени, что приводит к задержкам во время выполнения программы. Таким образом, движок разделит работу по сбору мусора на несколько подзадач и постепенно выполнит каждую небольшую задачу во время выполнения программы. Это вызовет определенную задержку восстановления, но обычно не вызывает явных задержек программы.
ПроцессорCPU
всегда работает даже в сложных программах. В основном это связано с тем, что CPU
работает очень быстро, а периферийный IO
часто на несколько порядков медленнее. Поэтому рекомендуется организовать стратегию сбора мусора, когда CPU
находится в режиме ожидания. холостой ход. Это очень эффективный метод оптимизации производительности, который практически не оказывает негативного воздействия на саму программу. Эта стратегия аналогична обновлению системы во время простоя, и пользователи вообще не знают о фоновом выполнении.
Основная задача этой статьи — просто покончить с механизмами сборки мусора, часто используемыми стратегиями и методами оптимизации. Она не предназначена для того, чтобы дать всем глубокое понимание принципов фонового выполнения движка.
Из этой статьи вы должны понять:
JavaScript
, которая выполняется в фоновом режиме и не требует от нас беспокойства по этому поводу.