Go
Basics
- If you receive "cannot find package" errors when importing a
package, either
export GO111MODULE=on
or create a module withgo mod init $MODULE
Hello World
helloworld.go:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Run:
$ go run helloworld.go
Hello, World!
Thread Dump
Built-in thread dump
By default, Go handles the
SIGQUIT
signal by printing a stack trace to
stdout/stderr although then it kills itself:
A SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, or SIGSYS signal causes the program to exit with a stack dump.
Manually generated thread dump
A thread dump may be manually generated by first calling pprof.Lookup
on the goroutine
profile and then writing that to a file with Profile.WriteTo
.
Heap Dump
Manually generated heap dump
A heap dump may be manually generated by calling debug.WriteHeapDump
.
Analyzing a Heap Dump from a Core Dump
If you have a core dump, its heap may be analyzed with viewcore
.
However, viewcore
requires that the
executable does not have stripped
symbols.
In addition, viewcore
is not very actively maintained
and there are known
issues as of this writing, so, in general, it's better to use
debug.WriteHeapDump
instead if possible.
Building viewcore
git clone https://github.com/golang/debug
cd debug
CGO_ENABLED=0 go build golang.org/x/debug/cmd/viewcore
Running viewcore
./viewcore core.dmp --exe targetexe
viewcore commands
Available Commands:
breakdown print memory use by class
goroutines list goroutines
help Help about any command
histogram print histogram of heap memory use by Go type
html start an http server for browsing core file data on the port specified with -port
mappings print virtual memory mappings
objects print a list of all live objects
objgraph dump object graph (dot)
overview print a few overall statistics
reachable find path from root to an object
read read a chunk of memory
Additional debugging
If additional debugging information is required, consider compiling the target program without optimizations and inlining:
make build GOFLAGS="-gcflags=all='-N -l'"
Signal processing
Go allows a program to handle various POSIX signals:
The functions in this package allow a program to change the way Go programs handle signals.
It also applies to some signals that otherwise cause no action: SIGUSR1, SIGUSR2
Therefore, it's valuable for any Go program to add a
SIGUSR1
handler to write a thread dump and a
SIGUSR2
handler to write a heapdump. For
example:
usr1 := make(chan os.Signal, 1)
signal.Notify(usr1, unix.SIGUSR1)
usr2 := make(chan os.Signal, 1)
signal.Notify(usr2, unix.SIGUSR2)
go func() {
for {
select {
case <- usr1:
f, err := os.Create("threaddump_" + time.Now().Format(time.RFC3339) + ".txt")
if err != nil {
// TODO handle error
continue
}
err = pprof.Lookup("goroutine").WriteTo(f, 2)
if err != nil {
// TODO handle error
continue
}
case <- usr2:
f, err := os.Create("heapdump_" + time.Now().Format(time.RFC3339) + ".bin")
if err != nil {
// TODO handle error
continue
}
debug.WriteHeapDump(f.Fd())
}
}
}()
Link options
Stripping symbols
Though not recommended for maintainability, it is common to use the
-s -w
link
options; for example:
go build -ldflags="-s -w"
This strips debugging symbols from the final executable:
-s Omit the symbol table and debug information. -w Omit the DWARF symbol table.
Although stripping
symbols is done for non-debug builds of some common executables such
as kubelet
, unless the size difference is very large or
there are security concerns about reverse engineering, it is generally a
net positive for maintenance to retain symbols by removing the
-s -w
link options. This will allow crash debugging,
viewcore
, some native stack walking tools, and it is not
expected to have a performance impact to retain symbols.