默认情况下,Go语言中哪些对象会被终结,并且有哪些潜在问题?

10

函数runtime.SetFinalizer(x, f interface{})设置与x关联的终结器为f

默认情况下,哪些对象会被终结器终结?

默认情况下终结对象可能会导致哪些意外问题?


请注意runtime.SetFinalizer文档中列出的许多警告。您永远不应该依赖于或期望最终器被执行。相反,始终确保调用适当的清理函数(例如,在检查os.Open的错误后立即使用defer file.Close())。 - Dave C
3个回答

11

以下对象默认情况下会被终结:

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

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

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

除了上述提到的对象类型之外,Go标准库不会为其他对象类型设置终结器。

在实际程序中,似乎只有一个潜在的问题可能会导致问题:当 os.File 被终止时,它将调用操作系统来关闭文件描述符。如果 os.File 是通过调用函数 os.NewFile(fd int, name string) *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

1
以上代码无论是粘贴到golang.org还是weekly.golang.org的playgrounds中,都会打印出some text - zzzz
@jnml:由于某种原因,playgrounds中os.File.Close()函数根本不起作用。请参见http://play.golang.org/p/qNj8LRXQny - user811773
截至Go 1.4.2版本(可能更早),此示例已正常运行。不清楚是否未调用终结器或已调用且现在“正确地执行了相应操作”。 - Dave C

5

只需查看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。
  • 当您打开一个新文件时,Go库将为返回的对象绑定一个Finalizer。
  • 当您不确定GC会对该对象做什么时,请跳转到源代码并检查库是否在该对象上设置了一些finalizers。

-4
"

默认情况下哪些对象会被完成?
在Go中,我认为没有任何东西被默认完成。

默认情况下完成这些对象会导致哪些意外缺陷?
根据上述情况:没有。

"

你能否创建一个Go程序,打开一个文件并且返回的*os.File对象没有开启终止(而不需要修改Go标准包的源代码)?如果你不能做到这一点,那么这意味着所有的os.File实例都默认开启终止。 - user811773
1
我在谈论Go语言,而不是任何库。 - zzzz
2
我在谈论整个Go语言(包括标准库)。 - user811773
@Atom:仍然一样。*os.File 会在包代码中 显式 设置 finalizer 才会被 finalized。在 Go 中,无论是在任何库中,都没有 "默认被 finalized" 的情况。 - zzzz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接