【问题标题】:Which objects are finalized in Go by default and what are some of the pitfalls of it?在 Go 中哪些对象是默认完成的,它有哪些陷阱?
【发布时间】:2011-12-21 19:49:11
【问题描述】:

函数@987654321@(x, f interface{}) 将与x 关联的终结器设置为f。

什么类型的对象默认被终结?

默认完成这些对象会导致哪些意外陷阱?

【问题讨论】:

  • 请注意runtime.SetFinalizer documentation 中列出的许多注意事项。您应该永远依赖或期望终结器永远运行。相反,始终确保调用适当的清理函数(例如,在检查 os.Open 的错误后立即调用 defer file.Close())。

标签: garbage-collection go finalizer


【解决方案1】:

默认情况下完成以下对象:

  • os.File: 对象被垃圾回收时文件自动关闭。

  • os.Process:终结将释放与进程相关的所有资源。在 Unix 上,这是一个无操作。在 Windows 上,它关闭与进程关联的句柄。

  • 在 Windows 上,net 包似乎可以自动关闭网络连接。

Go 标准库没有为上述对象类型设置终结器。

在实际程序中似乎只有一个潜在问题可能导致问题:当os.File 最终确定时,它将调用操作系统以关闭文件描述符。如果通过调用函数os.NewFile(fd int, name string) *File 创建了os.File,并且文件描述符也被另一个(不同的)os.File 使用,那么垃圾收集其中一个文件对象将呈现其他文件对象不可用。例如:

package main

import (
    "fmt"
    "os"
    "runtime"
)

func open() {
    os.NewFile(1, "stdout")
}

func main() {
    open()

    // Force finalization of unreachable objects
    _ = make([]byte, 1e7)
    runtime.GC()

    _, err := fmt.Println("some text") // Print something via os.Stdout
    if err != nil {
        fmt.Fprintln(os.Stderr, "could not print the text")
    }
}

打印:

could not print the text

【讨论】:

  • 以上代码在两种情况下都未更改地粘贴到 golang.org 和 week.golang.org 的游乐场打印:some text
  • @jnml: os.File.Close() 函数由于某种原因在操场上根本不起作用。见play.golang.org/p/qNj8LRXQny
  • 从 Go 1.4.2 开始(可能更早),这个例子运行良好。目前还不清楚终结器是否没有被调用,或者它是否被调用并且现在“做正确的事情”。
【解决方案2】:

直接进入os.NewFile的源代码:

// NewFile returns a new File with the given file descriptor and name.
func NewFile(fd uintptr, name string) *File {
    fdi := int(fd)
    if fdi < 0 {
        return nil
    }
    f := &File{&file{fd: fdi, name: name}}
    runtime.SetFinalizer(f.file, (*file).close)  // <<<<<<<<<<<<<<
    return f
}
  • 当 go 运行 GC 时,它会在该对象上运行 Finalizers bind。
  • 当您打开一个新文件时,go 库会为您在返回的对象上绑定一个终结器。
  • 当您不确定 GC 会对该对象执行什么操作时,请跳转到源代码并检查库是否在该对象上设置了一些终结器。

【讨论】:

    【解决方案3】:

    “什么类型的对象默认被终结?”
    Go 中的任何内容都未在 IMO默认情况下最终确定。

    “默认情况下完成这些对象会导致哪些意外陷阱?”
    如上:无。

    【讨论】:

    • 你是否可以创建一个 Go 程序来打开一个文件并且返回的 *os.File 关闭了 finalization(无需修改 Go 标准包的源代码)?如果您不能这样做,则意味着 os.File 的所有实例都已完成默认情况下。
    • 我说的是 Go,而不是任何库。
    • 我说的是整个 Go(包括标准包)。
    • @Atom:还是一样。 *os.File 通过显式在包代码中设置终结器来终结。 Go 中没有任何内容,任何库中都没有“默认完成”。
    猜你喜欢
    • 2011-12-11
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 2012-02-03
    • 1970-01-01
    • 2021-03-13
    相关资源
    最近更新 更多