在 Go 中转储 Goroutine 堆栈跟踪

Jay Singh 2022年4月22日
在 Go 中转储 Goroutine 堆栈跟踪

处理奇怪情况的惯用方法是在 Go 程序中使用错误。错误导致软件中出现的大多数异常情况。

但是,在极少数情况下,软件将由于异常状态而无法继续运行。在这种情况下,panic 可以提前结束程序。

当函数遇到 panic 时,函数的执行将停止,任何延迟的函数都将运行,并且控制权将返回给函数的调用者。

这个过程一直持续到所有当前 goroutine 的函数都返回,此时程序在终止之前打印 panic 消息,然后是堆栈跟踪。

当我们构建一个示例程序时,这将变得更加清晰。

在 Go 中使用 panic 转储 Goroutine 堆栈跟踪

这个简单的脚本将打印一个人的全名。fullName 函数返回一个人的全名。

此方法检查 firstNamelastName 指针中的 nil 值。如果它是 nil,该函数会发送一个带有消息的 panic 信号。

当程序完成时,它将打印此消息。

package main

import (
    "fmt"
)

func fullName(firstName *string, lastName *string) {
    if firstName == nil {
        panic("runtime error: first name cannot be nil")
    }
    if lastName == nil {
        panic("runtime error: last name cannot be nil")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}

func main() {
    firstName := "Jay"
    fullName(&firstName, nil)
    fmt.Println("returned normally from main")
}

输出:

panic: runtime error: last name cannot be nil

goroutine 1 [running]:
main.fullName(0x405058?, 0xc000070f70?)
    /tmp/sandbox885911142/prog.go:12 +0x114
main.main()
    /tmp/sandbox885911142/prog.go:20 +0x35

现在,下面的示例犯了一个常见错误,即尝试使用内置 len 提供的长度来访问切片的最终元素。

为了说明为什么这可能会导致恐慌,请运行以下代码。

package main

import (
    "fmt"
)
func main() {
    names := []string{
        "Iron Man",
        "Thor",
    }
    fmt.Println("My favorite superhero is:", names[len(names)])
}

输出:

panic: runtime error: index out of range [2] with length 2

goroutine 1 [running]:
main.main()
    /tmp/sandbox2746930010/prog.go:12 +0x1b