上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
- 1. 初始化
- 2. 内存分配
- 3. 垃圾回收
- 4. 并发调度
- 5. 通道
- 6. 延迟调用
- 7. 终结器
- 8. 其他
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
9.2.4 泄漏
如果通道一直处于阻塞状态,那么会导致 goroutine 无法结束和回收,形成资源泄露。
package main import ( "time" "runtime" ) func test() chan byte { c := make(chan byte) go func() { buf := make([]byte, 0, 10<<20) // 10MB for { d, ok := <- c if !ok { return } buf = append(buf, d) } }() return c } func main() { for i := 0; i < 5; i++ { test() } for { time.Sleep(time.Second) runtime.GC() } }
# 因 goroutine 无法结束,其持有的 buf 内存无法回收。 $ GODEBUG=gctrace=1 ./test gc 1 @0.002s 20%: ... 50->50->50 MB, 50 MB goal, ... gc 2 @1.002s 0%: ... 50->50->50 MB, 100 MB goal, ... (forced) gc 3 @2.009s 0%: ... 50->50->50 MB, 100 MB goal, ... (forced) ... gc 7 @6.029s 0%: ... 50->50->50 MB, 100 MB goal, ... (forced)
# 可以观察到这些 goroutine 的状态。 $ GODEBUG="schedtrace=1000,scheddetail=1" ./test SCHED 3008ms: gomaxprocs=2 idleprocs=2 threads=4 ... G1: status=4(sleep) G2: status=4(force gc (idle)) G3: status=4(GC sweep wait) G4: status=4(GC scavenge wait) G5: status=4(chan receive) m=-1 lockedm=-1 G6: status=4(chan receive) m=-1 lockedm=-1 G7: status=4(chan receive) m=-1 lockedm=-1 G8: status=4(chan receive) m=-1 lockedm=-1 G9: status=4(chan receive) m=-1 lockedm=-1 G10: status=4(GC worker (idle)) G11: status=4(GC worker (idle))
// src/runtime/runtime2.go const ( // G status // _Gidle means this goroutine was just allocated and has not // yet been initialized. _Gidle = iota // 0 // _Grunnable means this goroutine is on a run queue. It is // not currently executing user code. The stack is not owned. _Grunnable // 1 // _Grunning means this goroutine may execute user code. The // stack is owned by this goroutine. It is not on a run queue. // It is assigned an M and a P (g.m and g.m.p are valid). _Grunning // 2 // _Gsyscall means this goroutine is executing a system call. // It is not executing user code. The stack is owned by this // goroutine. It is not on a run queue. It is assigned an M. _Gsyscall // 3 // _Gwaiting means this goroutine is blocked in the runtime. // It is not executing user code. It is not on a run queue, // but should be recorded somewhere (e.g., a channel wait // queue) so it can be ready()d when necessary. The stack is // not owned *except* that a channel operation may read or // write parts of the stack under the appropriate channel // lock. Otherwise, it is not safe to access the stack after a // goroutine enters _Gwaiting (e.g., it may get moved). _Gwaiting // 4 // _Gmoribund_unused is currently unused, but hardcoded in gdb // scripts. _Gmoribund_unused // 5 // _Gdead means this goroutine is currently unused. It may be // just exited, on a free list, or just being initialized. It // is not executing user code. It may or may not have a stack // allocated. The G and its stack (if any) are owned by the M // that is exiting the G or that obtained the G from the free // list. _Gdead // 6 // _Genqueue_unused is currently unused. _Genqueue_unused // 7 // _Gcopystack means this goroutine's stack is being moved. It // is not executing user code and is not on a run queue. The // stack is owned by the goroutine that put it in _Gcopystack. _Gcopystack // 8 // _Gpreempted means this goroutine stopped itself for a // suspendG preemption. It is like _Gwaiting, but nothing is // yet responsible for ready()ing it. Some suspendG must CAS // the status to _Gwaiting to take responsibility for // ready()ing this G. _Gpreempted // 9 )
通过添加 time.After
之类手段,让通道有解除阻塞的机会。
另外,不当使用 time.Tick
,也会引发泄漏。(详情参考《中卷:标准库》)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论