TGViewer
Go Update Go Update @go_update · 3.22K subscribers
Post #69 5.13K
🧹 runtime: add AddCleanup - типобезопасная альтернатива SetFinalizer

Сейчас для отслеживания настоящего момента удаления объекта из памяти у нас есть одна функция: runtime.SetFinalizer. Она говорит рантайму, что нас (через коллбэк) нужно уведомить о том, что объект был убран из памяти сборщиком мусора. Чаще всего это нужно, чтобы мы не забыли закрыть внешние дескрипторы (файлы/сеть/прочее), ассоциированные с объектом.

Однако у этой функции есть и ряд минусов:
‣ Она не является типобезопасной. Вот вам простой пример кода, который развалится только во время выполнения.
‣ Она допускает "воскрешение мёртвых объектов" (ситуации, когда через финализатор можно вернуть данные по удаляемому указателю обратно к жизни - пример кода). Эту штуку кстати ребята из TailScale использовали в своей либе go4.org/intern. У них еще крутая статья есть.
‣ Нельзя поставить несколько финализаторов на объект. Это здорово мешает, когда есть дополнительные вещи которые мы хотим выполнить при «смерти» объекта, а автор вызываемого кода уже повесил свой финализатор. Обходные пути есть, но у всех них есть свои тонкости.

В качестве решения предложена функция AddCleanup вот с такой сигнатурой:


func AddCleanup[T, S any](ptr *T, cleanup func(S), arg S) Cleanup

type Cleanup struct { ... }

// Stop cancels the cleanup call.
func (c Cleanup) Stop() { ... }


Суть в том, что мы вешаем коллбэк на указатель (ptr), но в сам коллбэк приходит объект (arg) который мы ассоциировали с указателем.

Что это нам дает?
‣ Больше нельзя указать неправильную сигнатуру для коллбэка.
‣ Идет разделение между тем, что мы отслеживаем и тем, что мы получаем в коллбэк при «смерти» отслеживаемого. Более того, сама функция пытается уберечь нас от ситуаций типо arg == ptr (правда, только в рантайме).
‣ Сначала выполняется финализатор (если он есть), а затем выполняется один или более коллбэк который мы повесили с помощью нового механизма.

А ждет нас это счастье в Go 1.24, ведь само изменение уже в мастере.

LRU Cache Example

На самом деле я немного покривил душой, когда говорил про LRU кеш: получаемый кеш имеет часть его свойств, но нельзя точно указать число объектов которые будут живы в памяти и время их жизни. Те из вас кто работал с другими языками скорее всего узнают WeakMap в самом примере.

Главное:
‣ Создаем словарь/мапу ключей к слабым указателям.
‣ Удаляем ключ как сработает AddCleanup.

На этом всё - у вас есть минимальный пример самоочищающегося кеша.
pkg.go.dev intern package - go4.org/intern - Go Packages Package intern lets you make smaller comparable values by boxing a larger comparable value (such as a 16 byte string header) down into a globally unique 8 byte pointer.
  • 🔥 16
  • ❤ 4
  • 🤯 3
More from @go_update
  1. Aug 22, 2026Об изоляции LLM Да, это ещё один пост про работу с Codex/Claude/GLM/Qwen/DeepSeek и прочая…
  2. Aug 11, 2026И вот эти два минуса выглядят нерешенными (на данный момент времени). Можно ли их решить в…
  3. Aug 11, 2026🎂 Вечерний пост о том, что сегодня мне исполнилось 34. Прошёл еще один год, а значит врем…
  4. Jul 13, 2026📝 testing: allow examples with any signature Небольшое «Quality of Life» предложение. Сут…
  5. May 14, 2026📝 net/http/httptest: synctest support Я уже писал про пакет synctest и его возможности. Э…
  6. May 13, 2026Я редко пишу сюда о вещах которые не относятся к Go, но тут у меня появилась хорошая стать…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →