聊聊什么是 Go Runtime.KeepAlive?

开发 后端
有些同学喜欢利用 runtime.SetFinalizer 模拟析构函数,当变量被回收时,执行一些回收操作,加速一些资源的释放。在做性能优化的时候这样做确实有一定的效果,不过这样做是有一定的风险的。

[[436758]]

本文转载自微信公众号「HHFCodeRv」,作者haohongfan。转载本文请联系HHFCodeRv公众号。

有些同学喜欢利用 runtime.SetFinalizer 模拟析构函数,当变量被回收时,执行一些回收操作,加速一些资源的释放。在做性能优化的时候这样做确实有一定的效果,不过这样做是有一定的风险的。

比如下面这段代码,初始化一个文件描述符,当 GC 发生时释放掉无效的文件描述符。

  1. type File struct { d int } 
  2.  
  3. func main() { 
  4.     p := openFile("t.txt"
  5.     content := readFile(p.d) 
  6.  
  7.     println("Here is the content: "+content) 
  8.  
  9. func openFile(path string) *File { 
  10.     d, err := syscall.Open(path, syscall.O_RDONLY, 0) 
  11.     if err != nil { 
  12.       panic(err) 
  13.     } 
  14.  
  15.     p := &File{d} 
  16.     runtime.SetFinalizer(p, func(p *File) { 
  17.       syscall.Close(p.d) 
  18.     }) 
  19.  
  20.     return p 
  21.  
  22. func readFile(descriptor int) string { 
  23.     doSomeAllocation() 
  24.  
  25.     var buf [1000]byte 
  26.     _, err := syscall.Read(descriptor, buf[:]) 
  27.     if err != nil { 
  28.       panic(err) 
  29.     } 
  30.  
  31.     return string(buf[:]) 
  32.  
  33. func doSomeAllocation() { 
  34.     var a *int 
  35.  
  36.     // memory increase to force the GC 
  37.     for i:= 0; i < 10000000; i++ { 
  38.       i := 1 
  39.       a = &i 
  40.     } 
  41.  
  42.     _ = a 

上面这段代码是对 go 官方文档[1]的一个延伸,doSomeAllocation 会强制执行 GC,当我们执行这段代码时会出现下面的错误。

  1. panic: no such file or directory 
  2.  
  3. goroutine 1 [running]: 
  4. main.openFile(0x107a65e, 0x5, 0x10d9220) 
  5.         main.go:20 +0xe5 
  6. main.main() 
  7.         main.go:11 +0x3a 

这是因为 syscall.Open 产生的文件描述符比较特殊,是个 int 类型,当以值拷贝的方式在函数间传递时,并不会让 File.d 产生引用关系,于是 GC 发生时就会调用 runtime.SetFinalizer(p, func(p *File) 导致文件描述符被 close 掉。

什么是 runtime.KeepAlive ?

如上面的例子,我们如果才能让文件描述符不被 gc 给释放掉呢?其实很简单,只需要调用 runtime.KeepAlive 即可。

  1. func main() { 
  2.     p := openFile("t.txt"
  3.     content := readFile(p.d) 
  4.      
  5.     runtime.KeepAlive(p) 
  6.  
  7.     println("Here is the content: "+content) 

runtime.KeepAlive 能阻止 runtime.SetFinalizer 延迟发生,保证我们的变量不被 GC 所回收。

结论

正常情况下,runtime.KeepAlive,runtime.SetFinalizer 不应该被滥用,当我们真的需要使用时候,要注意使用是否合理。

 

责任编辑:武晓燕 来源: HHFCodeRv
相关推荐

2020-06-17 07:40:26

监控系统zabbix

2021-07-26 05:10:13

JavaJakarta EEJSR

2021-07-20 08:03:43

微服务应用程序

2021-02-05 08:42:21

云原生系统方式

2022-03-18 10:43:12

WebSocketHTML5TCP 连接

2022-10-28 08:46:57

变革型领导IT

2022-03-17 21:30:31

BRAS宽带服务器

2020-07-02 14:30:12

SDNSDON交换机

2023-05-14 19:18:07

2021-03-08 23:45:33

数字化转型5G

2015-09-07 09:53:02

Objective-CRuntime

2020-06-19 08:04:23

监控系统

2023-09-13 07:02:23

2021-11-11 09:27:02

技术RedisMySQL

2020-11-03 07:09:31

5GCPEWi-Fi

2020-08-07 14:28:04

裸金属服务器云服务

2022-05-31 09:17:08

通信网络技术

2023-01-12 08:52:50

GoroutinesGo语言

2022-02-26 19:05:01

AI人工智能机器学习

2023-12-05 17:57:13

nginx参数
点赞
收藏

51CTO技术栈公众号