- PVSM.RU - https://www.pvsm.ru -

Расширяем кругозор: Garbage Collector в V8

Всем привет, Хабрчане! Во время подготовки к очередному тех-собесу, я задался вопросом: а как в V8 работает Garbage Collector, что такое Heap и Stack, про которые я неоднократно слышал? После прочтения нескольких англоязычных и русскоязычных ресурсов понял, что одни копают очень глубоко, а другие дают лишь минимальную базу. Я решил сделать что-то среднее и с агрегировать все эти знания в одну статью, плавно погружая читателя в тему.

Кстати, я начинающий Node.js разработчик и это моя первая статья, прошу не судить строго :)

Погружаемся!

Расширяем кругозор: Garbage Collector в V8 - 1

Начнем с базы

Принцип сборки мусора довольно прост: если на сегмент в памяти никто не ссылается, например на объект, можно считать, что он (объект) не используется, и очистить его. Такой принцип ещё называют "принципом достижимости [1]".

Основной алгоритм сборки мусора называется mark-and-sweep [2]. Этот алгоритм может быть объединен также и с алгоритмом mark-compact [3]. Вместе они работают следующим образом:

  1. Сборщик мусора отмечает все корневые объекты.

  2. Далее помечаются все объекты, на которые ссылаются эти корни.

  3. Процесс повторяется для всех достижимых объектов.

  4. После этого непомеченные объекты считаются недостижимыми и удаляются.

  5. Происходит перемещение (дефрагментация) оставшихся объектов. Это уменьшит фрагментацию и повысит производительность выделения памяти для новых объектов.

mark-and-sweep + mark-compact

mark-and-sweep + mark-compact

Существует ещё несколько алгоритмов сборки мусора. Некоторые из наиболее распространенных алгоритмов включают:

  1. Serial Garbage Collector [4]

  2. Parallel Garbage Collector [5]

  3. Concurrent Mark and Sweep (CMS) [6]

  4. Garbage First (G1) [7]

Копаем глубже

Как в памяти V8 распределяются переменные, функции и объекты? V8 использует схему, основанную на концепции Java Virtual Machine (JVM) [8] и делит память на сегменты:

V8 memory schema
Расширяем кругозор: Garbage Collector в V8 - 3

  • Code Segment: выполняемый на данный момент код.

  • Stack (статическое выделение памяти): содержит все примитивные типы данных (вроде int, bool, string) с указателями на функции, объекты, а также информация о вызовах методов.

  • Heap (динамическое выделение памяти): сегмент памяти, предназначенный для хранения ссылочных типов данных, вроде объектов, массивов и функций. Это самый большой блок области памяти и именно здесь происходит сборка мусора.

Подробнее про каждый сегмент

Stack:

Это область памяти, выделенная для каждого процесса в V8. Здесь, как говорилось ранее, хранятся статические данные, включая фреймы методов/функций, примитивные значения и указатели на объекты. Стек работает по принципу LIFO (Last In, First Out) [9], то есть последний добавленный элемент будет первым извлеченным.

Heap – самый большой блок области памяти, под капотом он делиться на:

Heap schema
Расширяем кругозор: Garbage Collector в V8 - 4

  • Young generation - место, где "живут" новые объекты, и большинство из них недолговечны. Это пространство небольшое и состоит из двух полу-пространств (from-space, to-space).

  • Old generation - место, куда перемещаются объекты, которые пережили два цикла сборки мусора в Young generation блоке. Это пространство управляется основным алгоритмом сборки мусора mark-and-sweepOld generation можно поделить ещё на два подпространства:

    • Old pointer space - cодержит объекты, которые пережили два цикла сборки мусора, и имеют указатели на другие объекты.

    • Old data space – содержит исключительно объекты, которые имеют данные (без ссылок) и строки, числа, массивы.

  • Large object space – тут хранятся объекты, размер которых превышает размер других пространств. Большие объекты никогда не удаляются сборщиком мусора.

  • Code-space - Здесь Just In Time (JIT) [10] компилятор сохраняет скомпилированные блоки кода. Это единственное пространство с исполняемой памятью.

  • Cell space, property cell space, and map space – тут хранятся сервисные объекты, которые упрощают сборку мусора.

Заключение

Я надеюсь, что эта статья была полезной и интересной. Буду рад любым замечаниям и вопросам. Спасибо за внимание!

Вдохновлялся:

  1. A tour of V8: Garbage Collection [11]

  2. Visualizing memory management in V8 Engine (JavaScript, NodeJS, Deno, WebAssembly) [12]

  3. Устройство и работа JVM (Java Virtual Machine) [8]

  4. Эффективная работа с памятью в Node.js [13]

Мой репозиторий "Расширяем кругозор: Node.js и JavaScript" [14], где я записываю интересные ответы на вопросы и познаю дзен V8.

Автор: b1on1kkk

Источник [15]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/393565

Ссылки в тексте:

[1] принципом достижимости: https://learn.javascript.ru/garbage-collection#dostizhimost

[2] mark-and-sweep: https://ru.wikipedia.org/wiki/%D0%A1%D0%B1%D0%BE%D1%80%D0%BA%D0%B0_%D0%BC%D1%83%D1%81%D0%BE%D1%80%D0%B0

[3] mark-compact: https://en.wikipedia.org/wiki/Mark%E2%80%93compact_algorithm

[4] Serial Garbage Collector: https://proselyte.net/jvm-basics/#gc-sgc

[5] Parallel Garbage Collector: https://proselyte.net/jvm-basics/#gc-pgc

[6] Concurrent Mark and Sweep (CMS): https://proselyte.net/jvm-basics/#gc-cms

[7] Garbage First (G1): https://proselyte.net/jvm-basics/#gc-g1

[8] (JVM): https://proselyte.net/jvm-basics/

[9] LIFO (Last In, First Out): https://ru.wikipedia.org/wiki/LIFO

[10] (JIT): https://habr.com/ru/companies/oleg-bunin/articles/417459/

[11] A tour of V8: Garbage Collection: https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection

[12] Visualizing memory management in V8 Engine (JavaScript, NodeJS, Deno, WebAssembly): https://deepu.tech/memory-management-in-v8/

[13] Эффективная работа с памятью в Node.js: https://habr.com/ru/companies/ruvds/articles/433408/

[14] "Расширяем кругозор: Node.js и JavaScript": https://github.com/b1on1kkk/node-toolkit

[15] Источник: https://habr.com/ru/articles/836290/?utm_source=habrahabr&utm_medium=rss&utm_campaign=836290