Last active
February 19, 2020 09:27
-
-
Save komuw/0252dd7cd660edce4b483829dddfebc3 to your computer and use it in GitHub Desktop.
A Goroutines leak detector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
// or just use: | |
// 1. https://github.com/uber-go/goleak | |
// 2. github.com/cockroachdb/cockroach/pkg/util/leaktest | |
import ( | |
// "bytes" | |
"fmt" | |
"os" | |
"runtime" | |
"sort" | |
"strings" | |
"time" | |
) | |
func doWork() { | |
for { | |
<-time.After(1 * time.Second) | |
} | |
x := 1 + 1 | |
fmt.Println("x::", x) | |
} | |
func main() { | |
for i := 0; i < 10; i++ { | |
go doWork() | |
} | |
fmt.Println("work done") | |
if goroutineLeaked() { | |
fmt.Println("LEAAKED GOROUTINES") | |
} else { | |
fmt.Println("no leak") | |
} | |
} | |
// This code is taken from: https://github.com/golang/go/blob/d82e51a11973714708ddc7f9f055ae8ea3d509f1/src/net/http/main_test.go#L30-L141 | |
func goroutineLeaked() bool { | |
var stackCount map[string]int | |
for i := 0; i < 5; i++ { | |
n := 0 | |
stackCount = make(map[string]int) | |
gs := interestingGoroutines() | |
for _, g := range gs { | |
stackCount[g]++ | |
n++ | |
} | |
if n == 0 { | |
return false | |
} | |
// Wait for goroutines to schedule and die off: | |
time.Sleep(100 * time.Millisecond) | |
} | |
fmt.Fprintf(os.Stderr, "\n\t Too many goroutines running.\n") | |
for stack, count := range stackCount { | |
fmt.Fprintf(os.Stderr, "\n\t %d instances of: %s \n\n", count, stack) | |
} | |
return true | |
} | |
func interestingGoroutines() (gs []string) { | |
buf := make([]byte, 2<<20) | |
buf = buf[:runtime.Stack(buf, true)] | |
for _, g := range strings.Split(string(buf), "\n\n") { | |
sl := strings.SplitN(g, "\n", 2) | |
if len(sl) != 2 { | |
continue | |
} | |
stack := strings.TrimSpace(sl[1]) | |
if stack == "" || | |
strings.Contains(stack, "main.interestingGoroutines") || | |
strings.Contains(stack, "os/signal.signal_recv") || | |
// We may need to remove this ones since they only apply to the net/http package | |
// These only show up with GOTRACEBACK=2; Issue 5005 (comment 28) | |
strings.Contains(stack, "runtime.goexit") || | |
strings.Contains(stack, "created by runtime.gc") || | |
strings.Contains(stack, "net/http_test.interestingGoroutines") || | |
strings.Contains(stack, "runtime.MHeap_Scavenger") { | |
continue | |
} | |
gs = append(gs, stack) | |
} | |
sort.Strings(gs) | |
return | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
go run main.go | |
work done | |
Too many goroutines running. | |
10 instances of: main.doWork() | |
/Users/komuw/mystuff/naz/main.go:15 +0x41 | |
created by main.main | |
/Users/komuw/mystuff/naz/main.go:23 +0x42 | |
LEAAKED GOROUTINES |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We should actually reduce the if to;
we should add more things to that OR(||) as we need