пятница, 7 июня 2019 г.

V8 internals - отслеживание ссылок на объекты в куче V8

       То что спецификацию (как минимум первые версии) для языка JavaScript писали не очень умные люди с лихвой компенсируется мозгами тех кто пишет V8.  Чем больше разбираюсь в проекте - тем больше восхищаюсь этими людьми. И так - как же GC V8 узнает о ссылках на объекты в куче из C++ кода ? 
         Вся работа с объектами размещенными в куче построена на так называемых хендлерах. Так как GC может перемещать объекты размещенные в куче во время сборки мусора прямая работа с этими объектами (по указателю) запрещена. Все обращения только через хендлеры. Этих хендлеров есть несколько типов, все они объявлены в v8.h
  • Local - это хендлер время жизни которого ограничено временем жизни области видимости в которой он объявлен.  Как только мы выходим из области видимости - стэк отматывается и хендлер становится недействительным.
  • Persistent - это хендлер время жизни которого не контролируется областью видимости. Живет до тех пока явно не вызовешь Reset()
  • Global - тоже самое что и Persistent но c поддержкой move семантики
  • Eternal - это хендлер используемый для "вечных" ссылок. То есть ссылок живущих до тех пор пока жив Isolate. Они немного более удобны с точки зрения GC чем Persistent 
  • TracedGlobal - тоже самое что и Global но с подержкой трассировки GC. Для чего он может использоваться честно до конца не разобрался
Вся магия по управлению Local хэндлерами через область видимости реализуюется в классе HandleScope и Isolate.  Инстанс HandleScope обычно создается до создания первого хендлера. Все созданные после этого Local хэндлеры создаются в этой области видимости. HandleScope могут быть вложенными. При выходе за границы области видимости вызывается деструктор HandleScope  в котором происходит вызов HandleScope::CloseScope() который подчищает Local хэндлеры созданные в этой области видимости.  
        Тут собственно и начинается самое интересное. Выясняется что внутри Isolate (экземпляр виртуальной машины V8 со своей кучей и всем остальным) есть список буферов в которых собственно размещаются указатели на объекты размещенные в куче. val_ который хранится в Local хендлере это указатель на этот адрес, размещенный в буфере Isolate. Каждый раз когда мы создаем новый хендлер HandleScope::CreateHandle() выделает в буфере класса Isolate новый указатель который указывает на кучу. А возвращает указатель на этот указатель. Собственно когда нужно собрать мусор, GC пробегает по этому списку буферов заполнгенному указателями на кучу и помечает объекты как используемые. При перемещении объектов GC также меняет указатели если кто-то ссылается на этот объект. В общем получается весьма эффективная система.

Комментариев нет:

Отправить комментарий