首页 > 其他分享 >​解密 Go runtime.SetFinalizer 的使用

​解密 Go runtime.SetFinalizer 的使用

时间:2024-10-06 16:59:54浏览次数:7  
标签:GC func time Go SetFinalizer runtime

解密 Go runtime.SetFinalizer 的使用

原创 Go Official Blog Go Official Blog    2024年10月05日 18:45 中国香港 听全文

如果我们想在对象 GC 之前释放一些资源,可以使用 returns.SetFinalizer。这就像在函数返回前执行 defer 来释放资源一样。例如:

1:使用 runtime.SetFinalizer

type MyStruct struct {  
     Name  string  
     Other *MyStruct  
 }
 
 func main() {  
     x := MyStruct{Name: "X"}  
     runtime.SetFinalizer(&x, func(x *MyStruct) {  
        fmt.Printf("Finalizer for %s is called\n", x.Name)  
     })  
     runtime.GC()  
     time.Sleep(1 * time.Second)  
     runtime.GC()  
 }

官方文档[1]解释说,SetFinalizer 会将终结器函数与对象关联起来。当垃圾收集器(GC)检测到一个不可访问的对象有一个关联的终结器时,它会执行终结器并解除关联。如果该对象是不可到达的,并且不再有关联的终结器,那么它将在下一个 GC 周期被收集。

重要考虑因素

虽然 runtime.SetFinalizer 很有用,但有几个关键点需要注意:

  • 延迟执行:SetFinalizer 函数在对象被选中进行垃圾回收之前不会执行。因此,应避免将 SetFinalizer 用于将内存中的内容刷新到磁盘等操作。

  • 扩展对象生命周期:SetFinalizer 会无意中延长对象的生命周期。终结器函数会在第一个 GC 循环期间执行,目标对象可能会再次变得可触及,从而延迟其最终销毁。这在具有大量对象分配的高并发算法中可能会造成问题。

  • 循环引用的内存泄漏:与循环引用一起使用 runtime.SetFinalizer 可能会导致内存泄漏。

2:运行时.SetFinalizer 的内存泄漏

type MyStruct struct {  
     Name  string  
     Other *MyStruct  
 }  
   
 func main() {  
     x := MyStruct{Name: "X"}  
     y := MyStruct{Name: "Y"}  
   
     x.Other = &y  
     y.Other = &x  
     runtime.SetFinalizer(&x, func(x *MyStruct) {  
        fmt.Printf("Finalizer for %s is called\n", x.Name)  
     })  
     time.Sleep(time.Second)  
     runtime.GC()  
     time.Sleep(time.Second) 
     runtime.GC() 
 }

在这段代码中,对象 x 永远不会被释放。正确的方法是在不再需要该对象时,显式地移除终结器:runtime.SetFinalizer(&x, nil)。

实际应用

虽然 runtime.SetFinalizer 很少在业务代码中使用(我从未使用过),但它在 Go 源代码本身中使用得更为普遍。例如,考虑一下 net/http 包中的以下用法:

func (fd *netFD) setAddr(laddr, raddr Addr) {  
     fd.laddr = laddr  
     fd.raddr = raddr  
     runtime.SetFinalizer(fd, (*netFD).Close)  
 }  
   
 func (fd *netFD) Close() error {  
     if fd.fakeNetFD != nil {  
        return fd.fakeNetFD.Close()  
     }  
     runtime.SetFinalizer(fd, nil)  
     return fd.pfd.Close()  
 }

go-cache[2] 还展示了 SetFinalizer 的一个用法:

func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
   items := make(map[string]Item)
   return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
 }
 
 func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
   c := newCache(de, m)
   C := &Cache{c}
   if ci > 0 {
     runJanitor(c, ci)
     runtime.SetFinalizer(C, stopJanitor)
   }
   return C
 }
 
 func runJanitor(c *cache, ci time.Duration) {
   j := &janitor{
     Interval: ci,
     stop:     make(chan bool),
   }
   c.janitor = j
   go j.Run(c)
 }
 
 func stopJanitor(c *Cache) {
   c.janitor.stop <- true
 }
 
 func (j *janitor) Run(c *cache) {
   ticker := time.NewTicker(j.Interval)
   for {
     select {
     case <-ticker.C:
       c.DeleteExpired()
     case <-j.stop:
       ticker.Stop()
       return
     }
   }
 }

在 newCacheWithJanitor 中,当 ci 参数大于 0 时,会启动一个后台程序,通过 ticker 定期清理过期的缓存条目。一旦从停止通道读取到一个值,异步程序就会退出。

stopJanitor 函数定义了 Cache 指针 C 的终结器。当业务代码中不再引用 Cache 时,GC 进程会触发 stopJanitor 函数,并向内部 stop 通道写入一个值。这将通知异步清理 goroutine 退出,从而提供了一种优雅且与业务无关的资源回收方式。

参考资料[1]

SetFinalizer Doc: https://pkg.go.dev/runtime#SetFinalizer

[2]

go-cache: https://github.com/patrickmn/go-cache/blob/46f407853014144407b6c2ec7ccc76bf67958d93/cache.go#L1123

 

Go Official Blog

 你的肯定是对我最大的鼓励 

赞赏二维码稀罕作者

Go blog 合集131 Go blog 合集 · 目录 上一篇Some Go web dev notes 阅读 710   ​

标签:GC,func,time,Go,SetFinalizer,runtime
From: https://www.cnblogs.com/cheyunhua/p/18449203

相关文章

  • comp10002 Foundations of Algorithms
    comp10002 Foundations of AlgorithmsSemester 2,2024Assignment 2LearningOutcomesInthisproject,youwilldemonstrateyour understanding ofdynamic memory and linked data structures (Chap- ter 10) and extend your program design, testi......
  • Golang安全开发第一节
    Golang安全开发一、安装Go&编译器基础使用1.安装包地址https://golang.google.cn2.添加环境变量windows直接点击msi安装即可Linuxtar-zxvfxxx.xxx.xxx.tar.gzmv-rgo/use/local/govim/etc/profileexportPATH=$PATH:/usr/local/go/binsource/etc/profile3.......
  • 面向-MongoDB-开发者的-CosmosDB-教程-全-
    面向MongoDB开发者的CosmosDB教程(全)原文:CosmosDBforMongoDBdevelopers协议:CCBY-NC-SA4.0一、为什么是NoSQL?自从上学以来,我们大多数人都被教导要组织信息,这样它就可以用表格的形式来表示。但并不是所有的信息都能遵循这种结构,因此存在NULL值。NULL值表示没有信息......
  • HashiCorp联合创始人:Go是成功且无悔的选择
    HashiCorp联合创始人:Go是成功且无悔的选择TonyBai ​关注他 42人赞同了该文章 提到HashiCorp这个公司,可能很多人都没听说过。但提到vagrant、consul、nomad、terraform或者vault,那么你一定对这些工具或其中之一有所耳闻。这些工具都是HashiCorp这......
  • django + redis + celery 异步任务
    目录结构E:.│db.sqlite3│Dockerfile│manage.py│requirements.txt│├─celery_tasks#自定义一个celery的工作目录││config.py#celery配置文件││__init__.py│││├─sms│tasks.py#worker任务│__init__.py│......
  • Go-Micro客户端请求报500错误的解决方法
    Go-Micro客户端请求报500错误的解决方法1.服务端代码packagemainimport("github.com/gin-gonic/gin""github.com/micro/go-micro/registry""github.com/micro/go-micro/web""github.com/micro/go-plugins/registry/consu......
  • google chrome去除组织策略
    https://groups.google.com/g/huddcaricang/c/Bahkeds6vrg?pli=1https://hackerdose.com/downloads/utility/chrome-policy-remover/::ChromePolicyRemoverforWindows::version1.0-21May2022::CreatedbyStefanvd::ChromeProductExpert::https://prod......
  • 基于django+vue+Vue的高校设备信息管理系统的设计与实现【开题报告+程序+论文】-计算
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高校教育事业的蓬勃发展,各类教学科研设备的数量急剧增加,设备信息管理成为高校管理中的重要环节。传统的人工管理方式不仅效率低下,而且......
  • 基于django+vue+Vue的高校教师多维考核评价系统设计开发与实现【开题报告+程序+论文】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育的快速发展,高校教师的工作内容与职责日益复杂多样,传统的单一维度评价体系已难以满足当前对高校教师全面、公正评价的需求。近......
  • 基于django+vue+Vue的房屋租借系统【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着城市化进程的加速和人口流动性的增强,房屋租借市场日益繁荣,成为满足人们居住需求的重要途径。然而,传统的房屋租借方式往往依赖于中介或......