go 如何查看程序内存泄漏?
package main
import (
"fmt"
"net/http"
_ "net/http/pprof" // 自动注册pprof的handler
"time"
)
func main() {
// 启动pprof的HTTP服务
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
// 模拟协程泄漏
go leakedGoroutine()
// 保持程序运行
select {}
}
func leakedGoroutine() {
for {
time.Sleep(time.Second)
fmt.Println("泄漏的协程还在运行...")
}
}
查看trace
```html
goroutine profile: total 7
2 @ 0xaf4b0e 0xab8c77 0xaf3ce5 0xb47f47 0xb487e5 0xb494bb 0xbb3aa5 0xbbea45 0xc927b9 0xc3f543 0xc3fdc9 0xc40025 0xc41165 0xca17f0 0xca180b 0xc934c7 0xc980f8 0xafc6a1
# 0xaf3ce4 internal/poll.runtime_pollWait+0x84 D:/Program Files/Go/src/runtime/netpoll.go:351
# 0xb47f46 internal/poll.(*pollDesc).wait+0x26 D:/Program Files/Go/src/internal/poll/fd_poll_runtime.go:84
# 0xb487e4 internal/poll.execIO+0x104 D:/Program Files/Go/src/internal/poll/fd_windows.go:177
# 0xb494ba internal/poll.(*FD).Read+0x29a D:/Program Files/Go/src/internal/poll/fd_windows.go:438
# 0xbb3aa4 net.(*netFD).Read+0x24 D:/Program Files/Go/src/net/fd_posix.go:55
# 0xbbea44 net.(*conn).Read+0x44 D:/Program Files/Go/src/net/net.go:194
# 0xc927b8 net/http.(*connReader).Read+0x158 D:/Program Files/Go/src/net/http/server.go:798
# 0xc3f542 bufio.(*Reader).fill+0x102 D:/Program Files/Go/src/bufio/bufio.go:113
# 0xc3fdc8 bufio.(*Reader).ReadSlice+0x28 D:/Program Files/Go/src/bufio/bufio.go:380
# 0xc40024 bufio.(*Reader).ReadLine+0x24 D:/Program Files/Go/src/bufio/bufio.go:409
# 0xc41164 net/textproto.(*Reader).readLineSlice+0xa4 D:/Program Files/Go/src/net/textproto/reader.go:64
# 0xca17ef net/textproto.(*Reader).ReadLine+0xaf D:/Program Files/Go/src/net/textproto/reader.go:44
# 0xca180a net/http.readRequest+0xca D:/Program Files/Go/src/net/http/request.go:1087
# 0xc934c6 net/http.(*conn).readRequest+0x226 D:/Program Files/Go/src/net/http/server.go:1048
# 0xc980f7 net/http.(*conn).serve+0x397 D:/Program Files/Go/src/net/http/server.go:2027
1 @ 0xab57f1 0xaf395d 0xcc15d1 0xcc1405 0xcbe22b 0xcd788f 0xcd833e 0xc99c29 0xc9bac4 0xca2b0e 0xc98385 0xafc6a1
# 0xcc15d0 runtime/pprof.writeRuntimeProfile+0xb0 D:/Program Files/Go/src/runtime/pprof/pprof.go:796
# 0xcc1404 runtime/pprof.writeGoroutine+0x44 D:/Program Files/Go/src/runtime/pprof/pprof.go:755
# 0xcbe22a runtime/pprof.(*Profile).WriteTo+0x14a D:/Program Files/Go/src/runtime/pprof/pprof.go:377
# 0xcd788e net/http/pprof.handler.ServeHTTP+0x52e D:/Program Files/Go/src/net/http/pprof/pprof.go:272
# 0xcd833d net/http/pprof.Index+0xdd D:/Program Files/Go/src/net/http/pprof/pprof.go:389
# 0xc99c28 net/http.HandlerFunc.ServeHTTP+0x28 D:/Program Files/Go/src/net/http/server.go:2294
# 0xc9bac3 net/http.(*ServeMux).ServeHTTP+0x1c3 D:/Program Files/Go/src/net/http/server.go:2822
# 0xca2b0d net/http.serverHandler.ServeHTTP+0x8d D:/Program Files/Go/src/net/http/server.go:3301
# 0xc98384 net/http.(*conn).serve+0x624 D:/Program Files/Go/src/net/http/server.go:2102
1 @ 0xaf4b0e 0xab8c77 0xaf3ce5 0xb47f47 0xb487e5 0xb4a7a5 0xb4aad6 0xbb4b8b 0xbc583b 0xbc4a70 0xc9ce2c 0xc9ca31 0xcdd1f7 0xcdd1cf 0xafc6a1
# 0xaf3ce4 internal/poll.runtime_pollWait+0x84 D:/Program Files/Go/src/runtime/netpoll.go:351
# 0xb47f46 internal/poll.(*pollDesc).wait+0x26 D:/Program Files/Go/src/internal/poll/fd_poll_runtime.go:84
# 0xb487e4 internal/poll.execIO+0x104 D:/Program Files/Go/src/internal/poll/fd_windows.go:177
# 0xb4a7a4 internal/poll.(*FD).acceptOne+0x64 D:/Program Files/Go/src/internal/poll/fd_windows.go:946
# 0xb4aad5 internal/poll.(*FD).Accept+0x1b5 D:/Program Files/Go/src/internal/poll/fd_windows.go:980
# 0xbb4b8a net.(*netFD).accept+0x4a D:/Program Files/Go/src/net/fd_windows.go:182
# 0xbc583a net.(*TCPListener).accept+0x1a D:/Program Files/Go/src/net/tcpsock_posix.go:159
# 0xbc4a6f net.(*TCPListener).Accept+0x2f D:/Program Files/Go/src/net/tcpsock.go:380
# 0xc9ce2b net/http.(*Server).Serve+0x30b D:/Program Files/Go/src/net/http/server.go:3424
# 0xc9ca30 net/http.(*Server).ListenAndServe+0x70 D:/Program Files/Go/src/net/http/server.go:3350
# 0xcdd1f6 net/http.ListenAndServe+0x36 D:/Program Files/Go/src/net/http/server.go:3659
# 0xcdd1ce main.main.func1+0xe D:/workspace/GolandProjects/demo/day2/main.go:13
1 @ 0xaf4b0e 0xad3cc6 0xcdd14b 0xac1f3d 0xafc6a1
# 0xcdd14a main.main+0x2a D:/workspace/GolandProjects/demo/day2/main.go:20
# 0xac1f3c runtime.main+0x27c D:/Program Files/Go/src/runtime/proc.go:283
1 @ 0xaf4b0e 0xaf89c7 0xcdd178 0xafc6a1
# 0xaf89c6 time.Sleep+0x166 D:/Program Files/Go/src/runtime/time.go:338
# 0xcdd177 main.leakedGoroutine+0x17 D:/workspace/GolandProjects/demo/day2/main.go:25
1 @ 0xafc6a1
下面我们逐一分析每个goroutine组:
第一组:2个goroutine
堆栈显示它们正在等待网络I/O(internal/poll.runtime_pollWait),具体是在读取HTTP请求。这是正常的HTTP服务器行为,处理传入的请求。
第二组:1个goroutine
这个goroutine正在处理/debug/pprof的请求,具体是在写goroutine profile。这是我们在访问pprof端点时产生的,是正常的。
第三组:1个goroutine
这个goroutine在等待接受新的TCP连接(net.(*TCPListener).Accept),这是HTTP服务器监听新连接的部分,是正常的。
第四组:1个goroutine
这是主goroutine,正在执行main函数,是正常的。
第五组:1个goroutine
这个goroutine正在执行time.Sleep,位于函数main.leakedGoroutine中。根据函数名,这很可能是一个泄漏的goroutine,因为它只是一个简单的sleep,而且没有退出机制。
第六组:1个goroutine
这个goroutine的堆栈只有0xafc6a1,这可能是系统goroutine,例如垃圾回收等,但具体信息不足。不过,它可能是一个空闲的goroutine,或者是运行时有特殊用途的goroutine。
```
下面我们逐一分析每个goroutine组:
第一组:2个goroutine
堆栈显示它们正在等待网络I/O(internal/poll.runtime_pollWait),具体是在读取HTTP请求。这是正常的HTTP服务器行为,处理传入的请求。
第二组:1个goroutine
这个goroutine正在处理/debug/pprof的请求,具体是在写goroutine profile。这是我们在访问pprof端点时产生的,是正常的。
第三组:1个goroutine
这个goroutine在等待接受新的TCP连接(net.(*TCPListener).Accept),这是HTTP服务器监听新连接的部分,是正常的。
第四组:1个goroutine
这是主goroutine,正在执行main函数,是正常的。
第五组:1个goroutine
这个goroutine正在执行time.Sleep,位于函数main.leakedGoroutine中。根据函数名,这很可能是一个泄漏的goroutine,因为它只是一个简单的sleep,而且没有退出机制。
第六组:1个goroutine
这个goroutine的堆栈只有0xafc6a1,这可能是系统goroutine,例如垃圾回收等,但具体信息不足。不过,它可能是一个空闲的goroutine,或者是运行时有特殊用途的goroutine。
本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu
推荐文章: