Управление памятью в JS — это иллюзия, пока не начнутся падения RSS в production. WeakRef и FinalizationRegistry — не инструменты для ежедневного кода, а спасение в сценариях, где классические паттерны утечек уже вылечены, а память продолжает расти. В production это актуально для long-running SPA, тяжёлых кэшей на Node.js и интеграций с нативными ресурсами вроде Canvas.
WeakRef: кэш, который убивает сам себя
Когда Map с картинками или JSON-ответами держит сильные ссылки — это утечка, если объект больше не нужен. WeakRef позволяет хранить ссылку, которую GC может забрать при нехватке памяти. Используйте для кэширования тяжёлых данных или слабых подписок в Observer-паттерне.
class SmartCache {
private data = new Map<string, WeakRef<object>>();
set(key: string, value: object) {
this.data.set(key, new WeakRef(value));
}
get(key: string): object | undefined {
return this.data.get(key)?.deref();
}
}* Минус:
.deref() может вернуть undefined в любой момент — обрабатывайте это явно.FinalizationRegistry: cleanup для внешних ресурсов
Колбэк вызывается после сборки объекта. Нужен для освобождения WebSocket-соединений, файловых дескрипторов или памяти GPU. Не используйте для закрытия транзакций — колбэк может прийти с задержкой или не прийти до завершения процесса.
const registry = new FinalizationRegistry((id: string) => {
console.log(Cleanup: ${id});
});
class Heavy {
constructor(public id: string) {
registry.register(this, id);
}
}* Типичная ошибка: делать в колбэке тяжёлую работу — V8 может зависнуть event loop.
Где без них реально не обойтись
* Long-running SPA с вкладками, которые не пересоздаются.
* Canvas/WebGL: ручное управление памятью — часть архитектуры.
* Node.js: кэши изображений или HLS-фрагментов в высоконагруженных сервисах.
Что ломается в production
* V8 реализует WeakRef с задержками — мгновенной очистки не ждите.
* FinalizationRegistry может вызвать колбэк не в том порядке.
* Это не замена грамотному управлению ссылками, а дополнительный слой для узких мест.
Как избежать боли
Напишите модуль-обёртку: внутри WeakRef и Registry, снаружи чистый API с fallback на пересоздание или ошибку. Разработчику не нужно знать о слабых ссылках. Тестируйте с помощью
--expose-gc и следите за кучей в проде.Вывод:
WeakRef — для кэшей и подписок, FinalizationRegistry — для внешних ресурсов, но оба требуют явной обработки исчезновения объекта и не отменяют необходимость профилирования памяти.
