如果没有明确关闭,Go 会自动关闭资源吗? [英] Does Go automatically close resources if not explicitly closed?

查看:49
本文介绍了如果没有明确关闭,Go 会自动关闭资源吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下 Open 后跟延迟的 Close 在 Go 中是惯用的:

func example() {f, 错误 := os.Open(path)如果错误!= nil {返回}延迟 f.Close()}

如果我没有 defer f.Close() 会怎样?

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

如果它自动关闭,它到底什么时候执行此操作?

解决方案

确实如此垃圾收集时文件会关闭,但是...如Alexander Morozov -- LK4D4math 中的帖子/终结器/" rel="noreferrer">Go 中终结器的奥秘一个>:

<块引用>

在 Go 中,我们有 GC 和专业用户 :)
所以,在我看来显式调用 Close 总是比魔术终结器好.

亚历山大补充道:

<块引用>

终结器的问题在于您无法控制它们,而且更重要的是,您并不期待它们.

看看这段代码:

func getFd(path string) (int, error) {f, 错误 := os.Open(path)如果错误!= nil {返回-1,错误}返回 f.Fd(), nil}

<块引用>

当你为 linux 编写一些东西时,从路径中获取文件描述符是很常见的操作.
但是那个代码是不可靠的,因为当你从 getFd() 返回时,f 丢失了它的最后一个引用,所以你的文件迟早会被关闭(当下一个 GC 周期将到来).

这里的问题是不是文件将被关闭,而是文件没有记录并且根本不符合预期.

<小时>

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

但是……Russ Cox 令人信服地推翻了这一点:

<块引用>

对此主题感兴趣的任何人都应该阅读 Hans Boehm 的论文析构函数、终结器和同步".
它极大地影响了我们尽可能限制 Go 中终结器范围的决定.
它们是允许在回收相关堆内存的同时回收非(堆内存)资源的必要之恶,但它们的功能本质上比大多数人最初认为的要有限得多.

我们不会在实现或标准库或 x 存储库中扩展终结器的范围,也不会鼓励其他人扩展该范围.

如果您想跟踪手动管理的对象,最好使用 <代码>运行时/pprof.NewProfile.

例如,在 Google 的源代码树中,我们有一个 Google 范围的文件"抽象,并且为此的 Go 包装器包声明了一个全局:

var profiles = pprof.NewProfile("file")

<块引用>

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

profiles.Add(f, 2)返回 f

<块引用>

然后 f.Close

profiles.Remove(f)

<块引用>

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

The following Open followed by a deferred Close is idiomatic in Go:

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

What happens if I don't have defer f.Close()?

When I call this function and f goes out of scope, does it automatically close the file or do I have a zombie file handle?

If it closes automatically, when exactly does it do this?

解决方案

It is true Files are closed when garbage collected, but... as mentioned in "Mystery of finalizers in Go" from Alexander Morozov -- LK4D4math:

In Go we have both GC and pro-users :)
So, in my opinion explicit call of Close is always better than magic finalizer.

Alexander adds:

The problem with finalizers is that you have no control over them, and, more than that, you’re not expecting them.

Look at this code:

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

It’s pretty common operation to get file descriptor from path when you’re writing some stuff for linux.
But that code is unreliable, because when you’re return from getFd(), f loses its last reference and so your file is doomed to be closed sooner or later (when next GC cycle will come).

Here, the problem is not that file will be closed, but that it is not documented and not expected at all.


There was a proposal to extend the finalizer and detecting leaks (like file descriptor leaks)

But... Russ Cox quashed that down convincingly:

Anyone interested in this topic should read Hans Boehm's paper "Destructors, Finalizers, and Synchronization".
It greatly influenced our decision to limit the scope of finalizers in Go as much as possible.
They are a necessary evil for allowing reclamation of non-(heap memory) resources at the same time as associated heap memory, but they are inherently much more limited in their capabilities than most people initially believe.

We will not be expanding the scope of finalizers, either in implementation or in the standard library, or in the x repos, nor will we encourage others to expand that scope.

If you want to track manually-managed objects, you'd be far better off using runtime/pprof.NewProfile.

For example, inside Google's source tree we have a Google-wide "file" abstraction, and the Go wrapper package for this declares a global:

var profiles = pprof.NewProfile("file")

The end of the function that creates a new File says:

profiles.Add(f, 2)
return f

and then f.Close does

profiles.Remove(f)

Then we can get a profile of all in-use files, "leaked" or otherwise, from /debug/pprof/file or from pprof.Lookup("file").WriteTo(w, 0).
And that profile includes stack traces.

这篇关于如果没有明确关闭,Go 会自动关闭资源吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆