【问题标题】:How can I dump all a Go process's stacks without killing it?如何在不杀死 Go 进程的情况下转储所有 Go 进程的堆栈?
【发布时间】:2014-06-14 19:25:39
【问题描述】:

Go 进程正在运行。我想要

  1. 为每个 goroutine 转储堆栈跟踪
  2. 从外部看,不依赖于我在其源代码中添加的任何内容
  3. 没有杀死它。

我该怎么做?

这应该很容易——请求的功能是:https://code.google.com/p/go/issues/detail?id=2516,并且根据该线程的结论,已实现。那是两年多以前的事了。但是问题线程和提交都没有包含有关如何调用此功能的任何提示。

功能请求提到 SIGQUIT 作为 JVM 接受的信号以调用那里的相应功能。但 SIGQUIT 不是答案。至少在 go1.2 上,SIGQUIT 会执行 #1 和 #2,但也会终止进程。

前段时间有人在这里问了一个相关的问题:How to dump goroutine stacktraces? 但他们没有明确要求#2 或#3,没有一个答案符合#2,他们接受了一个不符合#2 的答案。所以这是一个不同的问题。

【问题讨论】:

  • 看起来您必须在程序中添加一些内容才能捕获 SIGQUIT 并运行您链接的答案中的代码。我在 Brad 的更改列表中没有看到任何暗示它添加了默认信号处理程序或类似内容的内容。

标签: go


【解决方案1】:

您可以使用如下代码设置这样的处理程序:

import (
    "fmt"
    "os"
    "os/signal"
    "runtime"
    "syscall"
)

func main() {
    sigChan := make(chan os.Signal)
    go func() {
        stacktrace := make([]byte, 8192)
        for _ = range sigChan {
            length := runtime.Stack(stacktrace, true)
            fmt.Println(string(stacktrace[:length]))
        }
    }()
    signal.Notify(sigChan, syscall.SIGQUIT)


    ...
}

SIGQUIT 信号现在将被捕获并发送到给定的通道。然后使用runtime.Stack 函数将堆栈跟踪格式化为准备好的缓冲区(如果大于缓冲区,则将其截断),然后打印。

【讨论】:

  • 不满足要求#2
  • sigChan 应该是缓冲信号吗?
【解决方案2】:

如果您使用的是 net/http,您可以通过调试处理程序访问 goroutine。如果你看下面的源码

http://golang.org/src/pkg/runtime/pprof/pprof.go

您将在第 62 行看到配置文件 goroutineProfile。此配置文件通过 writeGoroutine 写出。如果用 debug >= 2 调用 writeGoroutine,那么它将写出所有的 goroutine。

你应该可以curl http://localhost:<port>/debug/pprof/goroutine?debug=2 来丢弃所有的 goroutines。不幸的是,我没有看到任何对会调用该代码的信号处理程序的引用,但您可以在上面的源代码中查看有关 pprof 如何使用runtime.Stack 的引用,以便自己轻松实现这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-08
    相关资源
    最近更新 更多