Перевод статьи Ирины Шестак. Garbage collection in V8, an illustrated guide. Опубликовано с разрешения автора.
Это руководство отличается от тех, что я делала раньше, и содержит немного сопровождающего текста вместе с эскизами. Я подумала, что вся концепция сборки мусора и то, как она обрабатывается в javascript (или, точнее, в движках javascript), заслуживает более подробного объяснения. Я также хотела бы упомянуть, что это руководство предназначено для начинающих пользователей и не охватывает все аспекты управления памятью в V8 и другие его подробности. Если же вы хотите исследовать глубже, то я приложила ссылки на несколько ресурсов. Также, это руководство сосредоточено на ✨javascript✨ и, очевидно, что сборка мусора в нём отличается от сборки мусора в других языках, таких, как, например, C (примечание переводчика: в C/C++ нет автоматических сборщиков мусора).
Хорошо, давайте приступим.
V8, движок javascript (не путайте с вашим любимым томатным соком 🍹), компилирует и исполняет ваш прекрасно написанный javascript. V8 поставляется с основанным на поколения (generational), останавливающем-весь-мир (stop-the-world) сборщиком мусора (это я постараюсь объяснить ниже). Он поставляется с Chrome. Эквивалент от Mozilla это SpiderMonkey, а Chakra - от Microsoft. В любом случае, при запуске javascript вам нужен движок для его исполнения, и V8 - один из ваших вариантов, будь то в браузере или в среде node.js. (P.S. и всё это ✨опенсорс✨.)
Важнейшей задачей сборки мусора является возможность управления использованием памяти конкретной программой. Такие языки, как C, обычно могут подключаться к управлению памятью программы и выделять и освобождать её в контексте программы. ECMAScript, с другой стороны, не имеет интерфейса для доступа к управлению памятью (да, это означает отсутствие соответствующего API). Что, в общем-то, означает, что все права на управление памятью™ в программе передаются V8.
Поскольку у нас нет доступа к бесконечному объему памяти, работа сборщика мусора заключается в том, что нужно перебрать все объекты, для которых выделена память, и определить, мертвы они или нет. Те, которые живы, должны остаться в памяти, те, которые мертвы, удаляются, а память возвращается обратно в кучу.
Что такое куча? Куча - это неструктурированная область, из которой объекты получают выделенную память. Распределение является динамическим, поскольку размер / время жизни / количество объектов неизвестно, поэтому выделение и освобождение памяти происходит во время выполнения программы.
Поэтому, если мы посмотрим на конкурентную модель, куча работает непосредственно со стеком вызовов, так как объекты, отображаемые в стеке, требуют выделения памяти. Это будет выглядеть примерно так:
Базовая проверка того, жив или мертв объект, основана на том, может ли клиент или программа, выполняющая код, достичь его. Наиболее достижимый объект, как вы можете подумать, это, вероятно, объект, объявленный в корневой области видимости.
Некоторые C++ биндинги (или веб-API на клиенте) также являются частью корня, поэтому вы можете напрямую обращаться к методам типа setInterval
.
О достижимости можно также думать так: сможет ли другой объект или корневой объект получить его, и если да, то память, требуемая для этого объекта, сохраняется.
V8 выделяет память в куче при создании новых объектов или новых «указателей». (У javascript нет реальных указателей, поэтому 'указатели' технически просто копируют ссылки на исходный объект). В куче есть множество разных пространств для разных типов объектов, и она будет организована примерно так:
В целях сбора мусора V8 делит кучу на две части: молодое и старое пространство. Когда вы выполняете операции, требующие выделения памяти, V8 выделяет место в первой части. Когда вы продолжаете добавлять вещи в кучу, вы в конечном итоге исчерпываете память, поэтому V8 будет запускать очистку. Для вновь созданных объектов память выделяется очень быстро из короткой и быстрой коллекции, очищаемой на регулярной основе (для удаления уже мертвых объектов). Как только объекты «переживают» несколько (2, чтобы быть точными) циклов очистки, они переносятся в старое пространство, обрабатывающееся сборщиком мусора в отдельном цикле по факту заполнения.
Старые объекты - это те, которые пережили более одного цикла сборки мусора, то есть на них продолжают ссылаться другие объекты, и они должны оставаться в памяти. Обычно они не ссылаются на молодые объекты, но продолжают иметь ссылки на более старые объекты. Нежелательно допускать смешение поколений, так как это делает уборку менее чистой.
- memory management; мне нравится читать глоссарий, потому что вы обнаруживаете кучу замечательных вещей.
- это действительно хороший и детальный справочник по производительности v8.
- вы можете заглянуть в v8 wiki для получения большей информации о внутренней работе v8 и том, как отлаживать ваши проекты.
- о "частоте кадров" в firefox dev tools
- другое хорошее руководство V8 && garbage collection