如果未明确关闭,Go会自动关闭资源吗?

1 resources go

在Go语言中,以下内容Open带有延迟名称Close是惯用的:

func example() {
    f, err := os.Open(path)
    if err != nil {
        return
    }
    defer f.Close()
}
Run Code Online (Sandbox Code Playgroud)

如果没有我该怎么办defer f.Close()

当我调用此函数并f超出范围时,它会自动关闭文件还是具有僵尸文件句柄?

如果它自动关闭,那么什么时候才执行呢?

Von*_*onC 6

确实,垃圾回收时文件是关闭的,但是...如亚历山大·莫罗佐夫(Alexander Morozov)的Go终结器的奥秘-LK4D4math所述

在Go中,我们既有GC用户
,也有Pro-users用户:)因此,我认为显式调用Close总是比magic finalizer好

亚历山大补充说:

终结器的问题在于您无法控制它们,更重要的是,您不期望它们。

看下面的代码:

func getFd(path string) (int, error) {
    f, err := os.Open(path)
    if err != nil {
        return -1, err
    }
    return f.Fd(), nil
}
Run Code Online (Sandbox Code Playgroud)

在为Linux编写某些内容时,从路径获取文件描述符是很常见的操作。
但是该代码是不可靠的,因为当您从中返回时getFd()f它会丢失其最后一个引用,因此您的文件注定早晚要关闭(下一个GC周期到来时)。

在这里,问题在于文件将被关闭,而是没有文档记录和根本没有期望。


有人提议扩展终结器并检测泄漏(例如文件描述符泄漏)

但是... Russ Cox令人信服地将其消除:

对这个主题感兴趣的任何人都应该阅读Hans Boehm的论文“ Destructors,Finalizers和Synchronization ”。
它极大地影响了我们决定限制Go中终结器范围的决定。
它们是允许与关联的堆内存同时回收非(堆内存)资源的必不可少的手段,但与大多数人最初认为的一样,它们的能力固有地要受到限制。

无论是在实现中,在标准库中还是在x存储库中,我们都不会扩展终结器的范围,也不会鼓励其他人扩展该范围。

如果您要跟踪手动管理的对象,最好使用runtime/pprof.NewProfile

例如,在Google的源代码树中,我们有一个Google范围的“文件”抽象,为此的Go包装程序包声明了一个全局变量:

var profiles = pprof.NewProfile("file")
Run Code Online (Sandbox Code Playgroud)

创建新文件的函数结尾说:

profiles.Add(f, 2)
return f
Run Code Online (Sandbox Code Playgroud)

然后f.Close

profiles.Remove(f)
Run Code Online (Sandbox Code Playgroud)

然后,我们可以从/debug/pprof/file或从中获取所有正在使用的文件的配置文件,无论是“泄漏”还是其他pprof.Lookup("file").WriteTo(w, 0)
该配置文件包括堆栈跟踪。


Bur*_*dar 1

当 os.File 被垃圾收集时,文件将自动关闭。这似乎是通过 SetFinalizer 调用完成的,因此文件最终将被关闭,而不是在它变得无法访问后立即关闭。