Как работает сборщик мусора в JavaScript
Что проверяют
Понимаете ли вы принцип достижимости и знаете ли, из-за чего в браузере реально текут утечки.
Как отвечать
Движок собирает по достижимости. Есть набор корней: глобальный объект, стек вызовов, замыкания в живых функциях. Всё, до чего можно дойти по ссылкам от корней, считается живым, остальное собирается. Поэтому циклические ссылки не проблема: два объекта, ссылающиеся друг на друга, но недостижимые от корней, будут собраны.
Алгоритм в V8 поколенческий: новые объекты попадают в молодое пространство и собираются часто и дёшево копированием выживших, пережившие переезжают в старое, где работает пометка с уборкой и уплотнением. Часть работы идёт параллельно и инкрементально, чтобы не давать длинных пауз.
Управлять этим из кода нельзя: вызвать сборку вручную нечем, и это сознательное решение.
Что действительно важно на практике, это причины утечек:
- забытые таймеры и подписки:
setIntervalи обработчик события держат замыкание, а через него весь компонент; - ссылки на удалённые узлы DOM, сохранённые в массиве или в замыкании;
- растущие глобальные кэши без вытеснения;
- замыкания, случайно захватывающие крупный объект.
Для случаев, где ссылка не должна мешать сборке, есть WeakMap, WeakSet и WeakRef: они не удерживают объект.
Ищут утечки снимками кучи в DevTools: сделать снимок, поработать, сделать второй и сравнить, что не освободилось.
Где спотыкаются
Говорят про подсчёт ссылок и считают циклы неразрешимой проблемой.
Уверены, что в языке со сборщиком утечек не бывает.
Не снимают обработчики при размонтировании компонента.
Не знают про WeakMap и держат кэш, который не даёт освободить память.