Отказ от ответственности: эта статья является первой подписанной статьей Nuggets, и ее перепечатка без разрешения запрещена.
написать впереди
Мы знаем, что механизм сбора мусора выполняется движком.Существует много видов JS-движков (разные браузеры), и механизм сбора мусора немного отличается в некоторых деталях и оптимизации.В этой статье мы используем некоторые общие алгоритмы переработки, такие как отправную точку, а затем возьмем оптимизацию этого механизма от разработки двигателя V8 до настоящего времени в качестве примера (зачем брать V8 в качестве примера? Потому что у него большая доля рынка 😄 ), шаг за шагом, чтобы помочь нам понять механизм сборки мусора, потому что, только по-настоящему поняв механизм сборки мусора, мы сможем понять его позже. Проблемы с утечками памяти и ручным предотвращением и оптимизацией.
JavaScript — увлекательный язык, что вы знаете о его аспекте GC (сборки мусора)? Я думаю, что большинство людей приходят посмотреть некоторые вопросы интервью, чтобы понять сбор мусора из-за интервью.Перед официальным стартом я перечислю для вас несколько небольших вопросов.Вы можете сначала подумать над ответами, а затем прочитать статью с вопросами и ответы. Наконец, после прочтения этой статьи, если ваш ответ можно оптимизировать, вы получите
Каков механизм сбора мусора?
Как образуется мусор?
Почему сборка мусора?
Как работает сборка мусора?
Какие оптимизации делает движок V8 для сборки мусора?
Конечно, мы не просто для интервью, цель понять ГК раз и навсегда! Если вы не понимаете какую-то часть контента, не волнуйтесь, сначала прочитайте всю статью, чтобы понять ее содержание, а затем вернитесь и прочитайте ее внимательно, она будет намного понятнее, полна галантереи, пожалуйста, лайкните ее. сначала а потом смотреть
что такое ГК
GC
которыйGarbage Collection
, программа будет генерировать много垃圾
Эти мусор - это память, которую программа не использует или пространство памяти, которое было использовано ранее и не будет использоваться снова в будущем.GC
Он отвечает за фигню, потому что работает внутри двигателя, поэтому для нас это передок,GC
Этот процесс относительно нечувствителен, и операции, выполняемые этим набором относительно нечувствительных к нам двигателей, часто называют垃圾回收机制
охватывать
Конечно, не во всех языках естьGC
, общий язык высокого уровня будет поставляться сGC
,НапримерJava、Python、JavaScript
подожди, естьGC
язык, напримерC、C++
Подождите, тогда это требует, чтобы наши программисты управляли памятью вручную, что относительно хлопотно.
Образование отходов и зачем перерабатывать
Мы знаем, что создание базового типа, объекта, функции... все это должно занимать память при написании кода, но мы не обращаем на это внимания, потому что это выделяется для нас движком, нам не нужно явно выделять память вручную
Но задумывались ли вы когда-нибудь, что происходит, когда нам что-то больше не нужно? Как движок JavaScript находит его и очищает?
Возьмем простой пример
let test = {
name: "isboyjc"
};
test = [1,2,3,4,5]
Как показано выше, мы предполагаем, что это полный программный код.
мы знаемJavaScript
Справочный тип данных хранится в памяти кучи, а затем ссылка на фактический объект в памяти кучи сохраняется в памяти стека, поэтомуJavaScript
Операции над ссылочными типами данных в , работают со ссылкой на объект, а не на фактический объект. Можно просто понять, что адрес хранится в памяти стека, и этот адрес связан с фактическим значением в памяти кучи.
Приведенный выше код сначала объявляет переменнуюtest
, который ссылается на объект{name: 'isboyjc'}
, а затем мы переназначаем эту переменную объекту массива, что означает, что переменная ссылается на массив, тогда предыдущее отношение ссылки на объект исчезает, как показано ниже.
Отношения нет,то есть бесполезный объект.В это время,если оставить стоять,можно один-два.Если больше,память не выдержит,поэтому ее надо чистить (восстановлено).
Официальными словами, для работы программы требуется память.Пока программа запрашивает, операционная система или среда выполнения должны предоставлять память.Затем для непрерывно работающего сервисного процесса память должна быть освобождена вовремя, иначе использование памяти будет становится все выше и выше. Незначительно влияет на производительность системы, а в серьезных случаях может привести к сбою процесса.
Политика сбора мусора
В управлении памятью JavaScript есть концепция, называемая可达性
, то есть те значения, которые каким-то образом доступны или пригодны для использования, они гарантированно сохраняются в памяти, в противном случае недоступны и нуждаются в переработке
Что касается того, как перерабатывать, то на самом деле это вопрос о том, как найти эти недоступные объекты (мусор) и очистить их.JavaScript
Грубо говоря, принцип работы механизма сборки мусора заключается в том, чтобы регулярно находить те памяти (переменные), которые уже не используются, а затем освобождать их память.
Вы также можете удивиться, почему не в режиме реального времени выяснить бесполезную память и выпустить его? На самом деле, это очень просто, накладные расходы в реальном времени слишком велики
Мы можем добраться до этого существа в центре внимания, и вот как найти так называемый хлам?
Этот процесс включает в себя некоторые стратегии алгоритма.Существует много способов.Мы кратко представим два наиболее распространенных из них.
- Алгоритм развертки пометки
- алгоритм подсчета ссылок
Алгоритм развертки пометки
Стратегия
Mark-Sweep, в настоящее время вJavaScript引擎
Этот алгоритм является наиболее часто используемым, большинство браузеров до сих порJavaScript引擎
Все они используют алгоритм удаления пометок, но основные производители браузеров также оптимизировали этот алгоритм, и разные браузерыJavaScript引擎
Зависит от того, как часто выполняется сборка мусора.
Как и его название, этот алгоритм делится на标记
а также清除
Два этапа, этап маркировки помечает все активные объекты, а этап очистки уничтожает немаркированные (то есть неактивные объекты)
Вам может быть интересно, как маркировать переменные? На самом деле способов много, например, когда переменная входит в среду выполнения, инвертировать определенный бит (представляя метку двоичным символом), или можно вести два списка входящих переменных среды и выходящих переменных среды, можно свободно помещаемые переменные Существует много других способов перехода от одного списка к другому. На самом деле нам не важно как метить, важна его стратегия
Когда движок выполняет сборку мусора (используя алгоритм удаления меток), ему нужно обойти все объекты в памяти, чтобы пометить их от начальной точки, и существует множество начальных точек, которые мы называем набором根
объект, а так называемый корневой объект фактически включает в себя и не только в среде браузера全局Window对象
,文档DOM树
Ждать
Общий процесс всего алгоритма удаления меток выглядит следующим образом
- Сборщик мусора добавит метку ко всем переменным в памяти во время выполнения, предполагая, что все объекты в памяти являются мусором, все помечены как 0
- Затем начните обход с каждого корневого объекта и измените узел, который не является мусором, на 1.
- Очистить весь мусор, отмеченный как 0, уничтожить и вернуть пространство памяти, которые они занимают
- Наконец, измените отметку всех объектов в памяти на 0 и дождитесь следующего раунда сборки мусора.
преимущество
Преимущество алгоритма очистки меток только одно, то есть реализация относительно проста, а маркировка есть не что иное, как маркировка, а не маркировка, что позволяет пометить для него один двоичный бит (0 и 1), что составляет очень простой
недостаток
Алгоритм очистки метки имеет большой недостаток, то есть после очистки оставшееся место в памяти объекта не изменяется, что также приведет к тому, что свободное пространство памяти будет прерывистым.内存碎片
(Как показано на рисунке ниже), а поскольку оставшаяся свободная память не является целым блоком, это список памяти, составленный из памяти разного размера, что связано с проблемой выделения памяти
Предположим, нам нужен размер, когда мы создаем новый объект для выделения памятиsize
, так как свободная память является прерывистой и прерывистой, необходимо выполнить односторонний обход списка свободной памяти, чтобы выяснить, больше ли он или равенsize
Блок может быть выделен ему (как показано ниже)
Так как же найти нужный блок? Мы можем принять следующие три стратегии распределения
-
First-fit
, найти больше или равноsize
Блок возвращается немедленно -
Best-fit
, пройти весь свободный список, вернуть больше или равноsize
самый маленький блок -
Worst-fit
, пройтись по всему свободному списку, найти самый большой блок, а затем разрезать на две части, одну частьsize
размер и вернуть часть
Из этих трех стратегийWorst-fit
Коэффициент использования площадиFirst-fit
а такжеBest-fit
Например, учитывая скорость и эффективность распределенияFirst-fit
это более разумный выбор
Подводя итог, можно сказать, что у алгоритма или стратегии подметания есть два очевидных недостатка.
- фрагментация памяти, свободные блоки памяти являются прерывистыми, и может появиться много свободных блоков памяти.Также может случиться так, что не может быть найден подходящий блок при выделении объектов со слишком большим объемом памяти.
-
Распределение идет медленно, поскольку даже при использовании
First-fit
стратегия, действие которой остаетсяO(n)
операции, в худшем случае каждый раз проходить до конца, а из-за фрагментации эффективность выделения больших объектов будет ниже.
PS: метка прозрачного алгоритма недостатки
В конечном счете, недостатком алгоритма очистки меток является то, что свободная память является прерывистой из-за положения оставшихся объектов после очистки, поэтому, пока это решено, оба недостатка могут быть устранены идеально.
а такжеАлгоритм Марк-КомпактЕго можно эффективно решить.Его этап маркировки ничем не отличается от алгоритма очистки меток, за исключением того, что после завершения маркировки алгоритм сортировки меток перемещает живой объект (то есть объект, который не нуждается в очистке) в один конец памяти и, наконец, очистить границу памяти (как показано ниже)
алгоритм подсчета ссылок
Стратегия
Подсчет ссылок, который на самом деле является более ранним алгоритмом сборки мусора,对象是否不再需要
Упрощенное определение как对象有没有其他对象引用到它
, если нет ссылки на объект (нулевая ссылка), объект будет утилизирован механизмом сборки мусора.Этот алгоритм редко используется в настоящее время, потому что он имеет много проблем, но нам все еще нужно понять
Его стратегия состоит в том, чтобы отслеживать, сколько раз используется каждое значение переменной.
-
Когда переменная объявляется и ей присваивается ссылочный тип, количество ссылок на значение равно 1.
-
Если такое же значение присваивается другой переменной, счетчик ссылок увеличивается на 1.
-
Если значение переменной перезаписывается другим значением, количество ссылок уменьшается на 1
-
Когда количество ссылок на это значение становится равным 0, это означает, что переменная не используется, к этому значению нельзя получить доступ, пространство освобождается, и сборщик мусора очистит память, занятую значением, количество ссылок которого равно 0 во время работы.
Следующий пример
let a = new Object() // 此对象的引用计数为 1(a引用)
let b = a // 此对象的引用计数是 2(a,b引用)
a = null // 此对象的引用计数为 1(b引用)
b = null // 此对象的引用计数为 0(无引用)
... // GC 回收此对象
Этот способ очень простой? Это действительно просто, но вскоре после появления алгоритма подсчета ссылок он столкнулся с серьезной проблемой — циклической ссылкой, то есть объект A имеет указатель на объект B, а объект B также ссылается на объект A, как показано ниже в примере.
function test(){
let A = new Object()
let B = new Object()
A.b = B
B.a = A
}
Как показано выше, объекты A и B ссылаются друг на друга через свои соответствующие свойства.Согласно приведенной выше стратегии подсчета ссылок, их счетчики ссылок равны 2. Однако в функцииtest
После завершения выполнения объекты A и B подлежат очистке, но с помощью подсчета ссылок не будут очищены, потому что их счетчик ссылок не станет равным 0, если эта функция будет вызываться в программе несколько раз, это вызовет A много памяти не будет освобождено
Давайте посмотрим на это с точки зрения очистки метки.Когда функция завершается, оба объекта выходят за рамки, A и B будут очищены как неактивные объекты, напротив, счетчик ссылок не будет выпущен, Это также вызовет много бесполезного использования памяти, что является одной из причин, по которой позднее от подсчета ссылок отказались и стали использовать помеченную очистку.
В IE8 и более ранних версиях IE
BOM
а такжеDOM
Объект не роднойJavaScript
объект, которыйC++
осуществленный组件对象模型对象(COM,Component Object Model)
,а такжеCOM
Объекты собираются мусором с использованием алгоритма подсчета ссылок, поэтому, даже если браузер использует алгоритм маркировки-очистки, если он включаетCOM
Циклическая ссылка объекта по-прежнему не может быть переработана, например, две ссылки друг на друга.DOM
объект и т. д., и для разрешения циклической ссылки вам необходимо установить адрес ссылки наnull
чтобы разорвать связь между переменной и значением, на которое ранее ссылались, следующим образом// COM对象 let ele = document.getElementById("xxx") let obj = new Object() // 造成循环引用 obj.ele = ele ele.obj = obj // 切断引用关系 obj.ele = null ele.obj = null
Однако в IE9 и более поздних версиях
BOM
а такжеDOM
объекты меняются наJavaScript
объект, который позволяет избежать вышеперечисленных проблемОбратитесь к разделу 4.3.2 книги Advanced JavaScript Programming Fourth Edition здесь.
преимущество
Преимущества алгоритма подсчета ссылок станут намного яснее, если мы сравним очистку метки.Во-первых, счетчик ссылок будет переработан, когда значение ссылки равно 0, то есть в тот момент, когда он станет мусором, поэтому он может сразу перерабатывать мусор.
Алгоритм очистки меток необходимо выполнять время от времени, поэтому поток должен быть приостановлен на определенный период времени во время работы приложения (скрипт JS).GC
, Кроме того, алгоритм удаления меток должен пройти через активные и неактивные объекты в куче для очистки, а счетчик ссылок должен подсчитываться только тогда, когда на него ссылаются.
недостаток
Недостатки подсчета ссылок должны быть понятны всем.Во-первых, ему нужен счетчик, и этот счетчик должен занимать большую позицию, потому что мы не знаем верхней границы количества ссылок, и нет возможности решить проблему невозможности повторного использования циклических ссылок, что также является наиболее серьезным
Оптимизация сборщика мусора V8
Выше мы также говорили, что большинство браузеров теперь основаны на алгоритме удаления разметки, как и V8.Конечно, V8 должен был провести над ним некоторую оптимизационную обработку.Далее мы в основном рассмотрим механизм сборки мусора в V8.Оптимизация
Генерационный сбор мусора
Представьте себе, что упомянутый выше алгоритм очистки мусора проверяет все объекты в памяти при каждой сборке мусора, в этом случае для некоторых больших, старых и долгоживущих объектов это то же самое, что для новых, маленьких и короткоживущих объектов. Частая проверка объектов не есть хорошо, потому что первое занимает много времени и не нуждается в частой чистке, а второе как раз наоборот Как это оптимизировать? ? ? Приходят поколения
новое и старое поколение
Стратегия сборки мусора V8 в основном основана на механизме сборки мусора поколений.В V8 память кучи разделена на две области: новое поколение и старое поколение, и для управления сборкой мусора используются разные сборщики мусора.
Объект нового поколения — это объект с коротким временем выживания, короче говоря, это вновь сгенерированный объект, который обычно только поддерживает1~8M
Емкость объекта старого поколения — это объект с длительными событиями выживания или резидентной памятью, короче говоря, это объект, который выжил после сборки мусора нового поколения, и емкость обычно больше.
Размер всей динамической памяти V8 равен сумме памяти нового поколения и памяти старого поколения (как показано ниже).
Для сборки мусора в новой и старой областях памяти V8 использует два сборщика мусора для управления и контроля. В настоящее время мы будем называть сборщик мусора, который управляет новым поколением, сборщиком мусора нового поколения. Точно так же мы называем его сборщиком мусора нового поколения. сборщик мусора, который управляет старым поколением. Он называется сборщиком мусора старого поколения.
Сборщик мусора нового поколения
Объекты молодого поколения создаются посредствомScavenge
алгоритм сборки мусора, вScavenge算法
В конкретной реализации в основном используется метод репликации, а именноCheney算法
, давайте познакомимся поближе
Cheney算法
Куча памяти разделена на две части, одна из которых — это используемое пространство, которое мы пока будем называть使用区
, один - это пространство в состоянии ожидания, которое мы называем空闲区
,Как показано ниже
Вновь добавленные объекты будут храниться в области использования. Когда область использования почти заполнена, необходимо выполнить операцию очистки от мусора.
Когда начинается сборка мусора, сборщик мусора нового поколения помечает активные объекты в области использования.После завершения маркировки активные объекты в области использования будут скопированы в свободную область и отсортированы, а затем попадут в очистку мусора. фаза, то есть неактивные объекты будут очищаться. Наконец, выполните обмен ролями, превратите исходную область использования в свободную область и превратите исходную свободную область в область использования.
Когда объект все еще жив после нескольких копий, он будет рассматриваться как объект с длительным жизненным циклом, а затем будет перемещен в старое поколение и будет управляться стратегией сборки мусора старого поколения.
Существует и другая ситуация, если вы копируете объект в область ожидания, место в области ожидания занимает более 25%, тогда этот объект будет напрямую перемещен в более старое пространство, причина установки до 25% заключается в том, что после завершенияScavenge
После переработки свободная зона будет превращена в используемую область, и распределение памяти объекта будет продолжаться. Если доля слишком велика, последующее выделение памяти будет затронуто.
Сборка мусора старого поколения
По сравнению с новым поколением сборку мусора старого поколения легче понять.Как мы сказали выше, большинство объектов, которые занимают большое пространство и имеют большое время выживания, будут отнесены к старому поколению, потому что объекты в старом поколения, как правило, относительно велики, если оно разделено, как новое поколение, а затем скопировано, это займет очень много времени, что приведет к неэффективному выполнению повторного использования, поэтому сборщик мусора старого поколения управляет выполнением своей сборки мусора, и весь его процесс использует выше.Так называемый алгоритм маркировки-развертки
Первая фаза — это фаза маркировки, начиная с группы корневых элементов, рекурсивно обходя группу корневых элементов, элементы, которые могут быть достигнуты в процессе обхода, называются активными объектами, а элементы, которые не достигнуты, могут быть оценены как неактивные. объекты
На этапе очистки сборщик мусора старого поколения будет непосредственно очищать неактивные объекты, то есть данные.
Мы также упоминали ранее, что алгоритм очистки меток будет генерировать большое количество прерывистых фрагментов памяти после очистки.Слишком большая фрагментация приведет к тому, что большие объекты не смогут выделить достаточно непрерывной памяти, и V8 использует сортировку меток, о которой мы упоминали выше.Алгоритм для решения этой проблемы. проблема оптимизации пространства
Зачем вам поколения?
Как в подзаголовке, зачем вам генерация? Какие преимущества имеет этот механизм и какие проблемы он решает?
На самом деле, нельзя сказать, что это решает какую-то проблему, можно сказать, что это точка оптимизации.
Генерационный механизм использует некоторые новые, маленькие и недолговечные объекты в качестве нового поколения и использует небольшой участок памяти для быстрой очистки с высокой частотой, в то время как некоторые большие, старые и долгоживущие объекты используются в качестве старых. поколение, что делает его редким После осмотра механизм переработки и частота старого и нового поколения различны.Можно сказать, что появление этого механизма значительно повысило эффективность механизма сбора мусора.
Параллельная переработка (Parallel)
Прежде чем вводить параллелизм, мы должны сначала понять концепцию全停顿(Stop-The-World)
,мы все знаемJavaScript
Это однопоточный язык, он работает в основном потоке, блокируется во время сборки мусора.JavaScript
Выполнение скрипта должно дождаться завершения сборки мусора, прежде чем возобновить выполнение скрипта. Мы называем это поведение全停顿
например, когда-тоGC
нужно60ms
, то логика нашего приложения должна быть приостановлена60ms
, если один разGC
Если время слишком велико, это может вызвать проблемы, такие как зависание страницы для пользователей.
Так как есть одно исполнениеGC
В более трудоемкой ситуации, учитывая, что одному человеку сложно построить дом, как насчет двух человек, десяти человек...? Переходя на сторону программы, можно ли ввести несколько вспомогательных потоков для одновременной обработки, ускорит ли это скорость выполнения сборки мусора? Поэтому команда V8 внедрила параллельный механизм рециркуляции.
Так называемый параллельный, то есть одновременно, он относится к процессу выполнения сборщиком мусора в основном потоке, открытия нескольких вспомогательных потоков и одновременного выполнения одной и той же работы по переработке.
Проще говоря, используя параллельную переработку, если бы основной поток изначально работал один, то на это ушло бы 3 секунды, теперь для совместной работы с основным потоком вызываются 2 вспомогательных потока, и трое работают вместе 1 секунду Это все, но поскольку многие люди работают совместно, нам нужно добавить часть времени для совместной работы нескольких человек (накладные расходы на синхронизацию), чтобы она составляла 0,5 секунды, то есть после принятия параллельной стратегии это займет 3 секунды. жить за 1,5 секунды. это сделано
Однако, хотя это можно сделать за 1,5 секунды и время значительно сокращается, основной поток все же должен быть освобожден в течение 1,5 секунд, именно потому, что основной поток все еще должен быть освобожден, память этого процесса статична и не нужно учитывать.Ссылочное отношение объектов в памяти меняется, нужно только учитывать сотрудничество, и это очень просто реализовать
Объектное пространство нового поколения использует параллельную стратегию.В процессе сборки мусора запускается несколько потоков, отвечающих за операцию очистки мусора в новом поколении.Эти потоки одновременно перемещают данные в объектном пространстве в свободную область. В этом процессе, поскольку адрес данных будет меняться, необходимо также синхронно обновлять указатели, ссылающиеся на эти объекты, что является параллельным повторением
Инкрементная маркировка и ленивая очистка
Хотя параллельная стратегия, о которой мы упоминали выше, может повысить эффективность сборки мусора и может быть хорошо оптимизирована для сборщика мусора нового поколения, на самом деле это метод сборки мусора с полной паузой. , для этих крупных объектовGC
Даже если мы используем параллельную стратегию, это все равно может занять много времени.
Так, чтобы сократить время полной паузы, в 2011 году V8 оптимизировал маркировку старого поколения, перейдя с маркировки полной паузы на инкрементную маркировку.
что такое инкрементальный
Приращение кGC
Процесс маркировки разбит на множество маленьких шагов, после выполнения каждого маленького шага некоторое время выполняется логика приложения, так что один раунд завершается после многократного чередования.GC
Марка (как показано ниже)
Только представьте, что полныйGC
Обозначьте исполнение дробями, чтобы в каждом маленькомGC
После того, как метка выполнена, как сделать паузу для выполнения программы задачи, а потом как ее возобновить? Если мы находимся в полномGC
Что делать после приостановки помеченного блока, если связь помеченных ссылок на объекты в памяти изменяется при выполнении программы задачи?
Видно, что реализация инкрементной немного сложнее, чем параллельная.Соответствующие решения V8 для этих двух проблем — метод трехцветной маркировки и барьер записи.
Метод трехцветной маркировки (пауза и возобновление)
Мы знаем, что в старом поколении используется алгоритм очистки меток, и мы сказали в очистке меток выше, то есть до того, как будет использован инкрементный алгоритм, достаточно просто использовать черный и белый цвета для маркировки данных, и процесс маркировки выполняется после завершенияGC
Перед маркировкой сборщик мусора установит все данные в белый цвет, а затем сборщик мусора начнет с группы объектов и пометит все доступные данные как черные.После завершения обхода объекты данных, помеченные черным цветом, являются активными объектами, оставшиеся белые объекты данных являются мусорными объектами, подлежащими очистке
Если принята стратегия черно-белой маркировки, после того, как сборщик мусора выполнит период инкрементной сборки, основной поток получает возможность выполнить часть приложения после паузы.JavaScript
кода, а затем, когда сборщик мусора запускается снова, на этот раз память черно-белая, и мы не можем знать, куда идти дальше.
Для решения этой проблемы команда V8 применила особый подход:三色标记法
Метод трехцветной маркировки использует два бита маркировки для каждого объекта и рабочий лист маркировки для маркировки, а два бита маркировки кодируют три цвета: белый, серый, черный.
- Белый относится к немаркированным объектам
- Серый означает, что сам отмечен, переменные-члены (ссылочный объект объекта) не отмечены
- Черный цвет означает, что отмечены как переменные self, так и переменные-члены.
Как показано на картинке выше, поясняем этот процесс самым простым образом, изначально все объекты белые, а это значит, что ресайклер их не помечает, начинаем с набора корневых объектов, сначала помечаем этот набор корневых объектов как серый и вставить в лист маркеров, когда сборщик извлекает объект из листа маркеров и обращается к объекту, на который он ссылается, меняет свой цвет с серого на черный и превращает свой следующий объект, на который указывает ссылка, в серый
Таким образом, спускайтесь вниз до тех пор, пока не останется объектов, которые можно пометить серым, то есть не будет объектов, до которых можно добраться (нет ссылок), затем все оставшиеся белые объекты станут недостижимыми, то есть ждут утилизации (как показано на рисунке выше).C、E
буду ждать переработки)
После использования метода трехцветной маркировки нам намного проще возобновить выполнение.Мы можем напрямую судить о том, завершена ли вся маркировка, по наличию в текущей памяти серых узлов.Если серых узлов нет, переходим непосредственно к этап очистки.При восстановлении можно продолжить выполнение прямо с серого узла.
Операция маркировки метода трехцветной маркировки может выполняться инкрементально, без сканирования всего пространства памяти каждый раз, и может быть хорошо согласована с инкрементным восстановлением для выполнения некоторых операций паузы и восстановления, тем самым уменьшая全停顿
время
Барьеры записи (изменение ссылок поэтапно)
полныйGC
После того, как отмеченный блок приостанавливается, связь ссылки на отмеченный объект в памяти изменяется при выполнении программы задачи. Может быть нелегко понять, что ссылка изменяется постепенно. Давайте рассмотрим пример (как показано на рисунке)
если мы имеемA、B、C
На три объекта ссылаются по очереди, все отмечены черным цветом (активные объекты) в первом добавочном сегменте, а затем приостанавливаются, чтобы начать выполнение приложения, то есть сценария JavaScript, в который мы помещаем объект.B
на который указывает объектC
изменено на объектD
, затем возобновить выполнение следующего инкрементного сегмента
На самом деле объектC
Отношения ссылки больше нет, но в настоящее время оно черное (представляющее активный объект) на протяжении всего раунда.GC
не будет убиратьC
Да, но мы можем игнорировать это, потому что даже если этот раунд не очищается и ждать следующего раундаGC
Это также очистит, что не сильно повлияет на работу нашей программы.
Смотрим на новый объектD
Это исходный белый цвет.Согласно тому, что мы сказали выше, серых объектов больше нет, то есть после того, как все разметки будут завершены, он будет очищен.Вновь измененные белые объектыD
будет во втором туреGC
Фаза очистки повторяется, и ссылочное отношение повторяется, и объект может быть использован в нашей программе позже.D
Ну это точно не правильно
Чтобы решить эту проблему, инкрементная переработка V8 использует写屏障 (Write-barrier)
Механизм, то есть, как только черный объект ссылается на белый объект, механизм заставит указанный белый объект измениться на серый, тем самым обеспечив следующее приращение.GC
Фаза маркировки может правильно маркировать, этот механизм также называется强三色不变性
В нашем примере выше объектB
на который указывает объектC
изменить на объектD
после белого объектаD
будет вынужден поседеть
Ленивая очистка
Инкрементный тег фактически отмечается на активном объекте и неактивном объекте.Для реальной очистки освобождения памяти V8 используется ленивая подметка.
После завершения инкрементной маркировки начинается ленивая очистка. Когда инкрементная маркировка завершена, если текущей доступной памяти достаточно, чтобы позволить нам быстро выполнить код, на самом деле нам не нужно очищать память немедленно, мы можем немного задержать процесс очистки, чтобыJavaScript
Код скрипта выполняется первым, и нет необходимости очищать всю память неактивных объектов за один раз, вы можете очищать по одному по мере необходимости, пока вся память неактивных объектов не будет очищена, а затем выполнять добавочную разметку
Плюсы и минусы инкрементной маркировки по сравнению с ленивой очисткой?
Появление добавочной разметки и ленивой очистки значительно сокращает время паузы основного потока, делая процесс взаимодействия пользователя с браузером более плавным. Но так как каждая маленькая добавочная метка выполняется междуJavaScript
Код, указатель объекта в куче мог измениться, и для записи изменений этих ссылочных отношений нужно использовать технологию барьера записи, так что недостаток инкрементной маркировки тоже очевиден:
Во-первых, это не уменьшает общее время паузы основного потока, а даже немного увеличивает его, во-вторых, из-за стоимости механизма барьера записи инкрементальная маркировка может снизить производительность приложения (само собой разумеется, что пропускная способность есть)
Параллельная переработка (Concurrent)
Ранее мы говорили, что параллельная переработка по-прежнему будет блокировать основной поток.Инкрементная маркировка также имеет два недостатка, увеличивая общее время паузы и снижая пропускную способность приложения.Так как же мы можем выполнять сборку мусора, не блокируя основной поток и согласуясь с приращение? более эффективно, чем?
Речь идет о параллельной переработке, которая относится к выполнению основного потока.JavaScript
Во время процесса вспомогательный поток может завершить операцию по сбору мусора в фоновом режиме.Когда вспомогательный поток выполняет сборку мусора, основной поток также может выполняться свободно без приостановки (как показано на рисунке ниже)
Когда вспомогательный поток выполняет сборку мусора, основной поток также может свободно выполняться без приостановки.Это преимущество параллелизма, но это также и сложность реализации параллельной сборки, поскольку необходимо учитывать выполнение основного потока.JavaScript
В настоящее время отношение ссылки на объект в куче может измениться в любое время.В это время некоторые метки, сделанные до или в процессе выполнения вспомогательным потоком, будут изменены, поэтому необходимо реализовать некоторые дополнительные механизмы блокировки чтения-записи для управления это. , мы не будем здесь подробно останавливаться
Давайте поговорим об оптимизации GC в V8.
Стратегия сборки мусора V8 в основном основана на механизме сборки мусора поколения.Как мы уже говорили о сборщике мусора нового поколения, мы сказали, что использование параллельной сборки может значительно повысить эффективность сборки мусора.Какая стратегия делает старое поколение использование сборщика мусора?шерстяная ткань? Выше я упоминал, что параллельная переработка, инкрементная маркировка и ленивая очистка, а также параллельная переработка — это несколько методов переработки для повышения эффективности и оптимизации опыта. Кажется, что один лучше другого. Какую стратегию использует сборщик мусора старого поколения? Это параллелизм? ? Внутренний монолог: «Похоже… похоже… одновременная переработка наиболее эффективна».
На самом деле эти три метода имеют свои преимущества и недостатки, поэтому в сборщике мусора старого поколения эти стратегии используются в комбинации.
Старое поколение в основном использует параллельную маркировку, и основной поток начинает выполняться.JavaScript
, вспомогательная нить одновременно выполняет операцию маркировки (вся операция маркировки завершается вспомогательной нитью)
После завершения маркировки выполнить параллельную операцию очистки (когда основной поток выполняет операцию очистки, несколько вспомогательных потоков также выполняют операцию очистки одновременно)
В то же время задачи очистки будут группироваться в каждом пакете постепенно.JavaScript
Выполнение между задачами
наконец
Выше приведены некоторые из основных оптимизаций, которые движок V8 сделал для нашей сборки мусора.Хотя движок оптимизирован, это не означает, что мы можем полностью игнорировать сборку мусора.Наш код по-прежнему должен активно избегать некоторых неблагоприятных вещей. выполняет операции по сбору мусора, потому что не вся бесполезная объектная память может быть утилизирована.Когда память, которая больше не используется, не утилизируется вовремя, мы называем это内存泄漏
Об утечках памяти — это еще один момент, и он не включен в эту статью из-за недостатка места.
Закончив работу, я дочитал ее, у вас есть более глубокий ответ на вопрос в начале? В предыдущем интервью я задавал интервьюеру такой вопрос.Большинство ответов студентов сводились к двум понятиям снятие меток и подсчет ссылок.Покопаться в глубинах различных дефектов и оптимизации не смог сказать.На самом деле мы комбинированный Было бы лучше, чтобы двигатель V8 оптимизировал сборку мусора, чтобы ответить на вышеуказанные вопросы.Тогда, пожалуйста, напишите свое понимание в области комментариев!
Кроме того, если есть какие-либо точки, которые не получены Get, вы можете прокомментировать и оставить сообщение, и добро пожаловать, чтобы указать на ошибки! ! !