我有Java背景,并且喜欢使用信号QUIT检查Java线程转储。
如何让Golang打印出所有goroutine堆栈跟踪?
Answers:
要打印当前goroutine的堆栈跟踪,请使用PrintStack()
fromruntime/debug
。
PrintStack将Stack返回的堆栈跟踪打印到标准错误。
例如:
import(
"runtime/debug"
)
...
debug.PrintStack()
要打印所有goroutine的堆栈跟踪,请使用Lookup
和WriteTo
从runtime/pprof
。
func Lookup(name string) *Profile
// Lookup returns the profile with the given name,
// or nil if no such profile exists.
func (p *Profile) WriteTo(w io.Writer, debug int) error
// WriteTo writes a pprof-formatted snapshot of the profile to w.
// If a write to w returns an error, WriteTo returns that error.
// Otherwise, WriteTo returns nil.
每个配置文件都有一个唯一的名称。预定义了一些配置文件:
goroutine-当前所有goroutine
堆的堆栈跟踪-所有堆分配的采样
threadcreate-导致创建新OS线程
块的堆栈跟踪-导致对同步原语进行阻塞的堆栈跟踪
例如:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack
。“堆栈返回调用它的goroutine的格式化堆栈跟踪。对于每个例程,它包括源行信息和PC值,然后尝试为Go函数发现调用函数或方法以及包含该行的文本。调用。”
runtime/pprof
Intermernet的答案中提到了该程序包的HTTP前端。导入net / http / pprof软件包以注册HTTP处理程序/debug/pprof
:
import _ "net/http/pprof"
import _ "net/http"
如果您还没有HTTP侦听器,请启动它:
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
然后将浏览器指向http://localhost:6060/debug/pprof
菜单或http://localhost:6060/debug/pprof/goroutine?debug=2
完整的goroutine堆栈转储。
您还可以通过这种方式来了解运行代码的其他有趣之处。查看博客文章,获取示例和更多详细信息:http : //blog.golang.org/profiling-go-programs
为了模仿SIGQUIT上的堆栈转储的Java行为,但仍使程序运行:
go func() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGQUIT)
buf := make([]byte, 1<<20)
for {
<-sigs
stacklen := runtime.Stack(buf, true)
log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
}
}()
与Java类似,SIGQUIT可用于打印Go程序及其goroutine的堆栈跟踪。
但是,关键的区别在于,默认情况下,将SIGQUIT发送到Java程序不会终止它们,而Go程序却会退出。
这种方法不需要更改代码即可打印现有程序的所有goroutine的堆栈跟踪。
环境变量GOTRACEBACK(请参见运行时包的文档)控制生成的输出量。例如,要包括所有goroutine,请设置GOTRACEBACK = all。
堆栈跟踪的打印是由意外的运行时条件(未处理的信号)触发的,该条件最初记录在此commit中,使其至少从Go 1.1起可用。
或者,如果可以选择修改源代码,请参见其他答案。
请注意,在Linux终端中,可以使用组合键Ctrl+方便地发送SIGQUIT \。
您可以使用runtime.Stack来获取所有goroutine的堆栈跟踪:
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
从文档中:
func Stack(buf []byte, all bool) int
堆栈将调用goroutine的堆栈跟踪格式格式化为buf,并返回写入buf的字节数。如果全部为真,则堆栈格式会将所有其他goroutine的跟踪信息堆叠到当前goroutine的跟踪信息之后的buf中。
string(buf)
这里做,fmt.Printf("%s", buf)
并且fmt.Printf("%s", string(buf))
做完全相同的事情(请参阅docs以获取fmt
软件包);唯一的区别是该string
版本将buf
不必要地复制字节
按CTRL + \
(如果您在终端中运行它,而只是想杀死程序并转储go例程等)
我发现这个问题正在寻找关键序列。只是想要一种快速简便的方法来判断我的程序是否泄漏了例程:)
在* NIX系统(包括OSX)上,发送信号中止SIGABRT
:
pkill -SIGABRT program_name
必须使用返回的长度,runtime.Stack()
以避免在堆栈跟踪之后打印一堆空行。以下恢复功能将打印出格式正确的跟踪:
if r := recover(); r != nil {
log.Printf("Internal error: %v", r))
buf := make([]byte, 1<<16)
stackSize := runtime.Stack(buf, true)
log.Printf("%s\n", string(buf[0:stackSize]))
}
默认情况下,^\
按键(CTRL + \)转储所有goroutine的堆栈跟踪。
否则,要进行更精细的控制,可以使用panic
。从Go 1.6+开始的简单方法:
go func() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGQUIT)
<-s
panic("give me the stack")
}()
然后,像这样运行程序:
# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
如果您还想打印go runtime例程:
$ GOTRACEBACK=system go run main.go
以下是所有GOTRACEBACK选项:
GOTRACEBACK=none
完全省略goroutine堆栈跟踪。GOTRACEBACK=single
(默认)的行为如上所述。GOTRACEBACK=all
为所有用户创建的goroutine添加堆栈跟踪。GOTRACEBACK=system
就像“ all”一样,但是为运行时函数添加了堆栈框架,并显示了运行时在内部创建的goroutine。GOTRACEBACK=crash
就像``系统''一样,但是以特定于操作系统的方式崩溃而不是退出。例如,在Unix系统上,崩溃引发SIGABRT
了核心转储。GOTRACEBACK变量控制在Go程序由于未恢复的紧急情况或意外的运行时条件而失败时生成的输出量。
默认情况下,故障将打印当前goroutine的堆栈跟踪,清除运行时系统内部的函数,然后以退出代码2退出。如果没有当前goroutine或故障是失败,则故障将打印所有goroutine的堆栈跟踪。在运行时内部。
由于历史原因,GOTRACEBACK设置0、1和2分别是none,all和system的同义词。
运行时/调试包的SetTraceback函数允许在运行时增加输出量,但不能将其减少到环境变量指定的量以下。参见https://golang.org/pkg/runtime/debug/#SetTraceback。