文件、Socket、GPU 句柄和 C 内存都不受 Go 垃圾回收器直接管理。理想情况下,调用方会及时执行 Close,但复杂控制流中总有可能遗漏。过去,库作者常用 runtime.SetFinalizer 增加最后一道保险;然而 finalizer 会让对象重新变得可达,还要处理依赖顺序和引用环,稍有不慎就永远不会执行。Go 1.24 引入了 runtime.AddCleanup,把“观察包装对象的生命周期”和“释放底层资源”拆开,减少了 finalizer 常见的可达性陷阱。需要先说清楚:它仍然不是确定性析构,也不能取代显式 Close,更准确的定位是资源泄漏的兜底机制。
AddCleanup 是一个泛型函数,核心签名如下:
func AddCleanup[T, S any](ptr *T, cleanup func(S), arg S) Cleanup