go语言基础学习八
goroutine什么情况会发生内存泄漏?如何避免#
定义:#
多个 goroutine 并发读写同一个共享变量,且没有同步保护,读写时序不确定,导致结果随机错误,就是竞态。
常见触发场景#
共享全局 / 结构体成员变量并发读写(最普遍)
map 并发写:map 非并发安全,多 goroutine 同时写入直接 panic
slice 并发修改底层数组:只读没问题,同时修改元素触发竞态
无保护的指针变量并发赋值
4 种主流解决手段#
(1) sync.Mutex/sync.RWMutex(互斥锁 / 读写锁)#
var (
cnt int
mu sync.Mutex
)
func add() {
for i := 0; i < 1000; i++ {
mu.Lock()
cnt++
mu.Unlock()
}
}
channel 串行化(Go 推荐:不要通过共享内存通信,用通信共享内存)#
把变量归属单个 goroutine,其他协程通过 channel 发请求修改。
sync/atomic 原子操作(只适用于基础数值:int/uint/pointer)#
var cnt int64
atomic.AddInt64(&cnt,1)
排查工具:go race#
go run -race main.go go build -race
如果若干个goroutine,有一个panic会怎么做?#
子 goroutine 发生 panic,没 recover#
当前 panic 协程直接终止,栈打印崩溃日志
主 goroutine (main 协程) panic#
main是程序入口 goroutine,main 一旦 panic 无 recover,整个 Go 进程立刻退出,所有正在运行 goroutine 全部强制销毁。
panic 被 recover() 捕获#
recover()只能在 defer 函数内生效,捕获后: 当前 goroutine 从 panic 恢复,继续往下执行; 完全不影响其他任何 goroutine。
defer可以捕获goroutine的子goroutine吗?#
父 goroutine 的 defer + recover 抓不到子 goroutine 的 panic,互不生效。
func main() {
defer func() {
if e := recover(); e != nil {
fmt.Println("想抓子协程panic,抓不住")
}
}()
go func() {
panic("子goroutine崩溃") // 父defer完全捕获不到,程序打印panic堆栈、主协程继续运行
}()
time.Sleep(1 * time.Second)
fmt.Println("main正常结束")
}
channel 死锁的场景#
当一个channel中没有数据,而直接读取时,会发生死锁#
q := make(chan int,2)
<-q
解决方案是采用select语句,再default放默认处理方式
q := make(chan int,2)
select{
case val:=<-q:
default:
...
}
向一个关闭的channel写数据#
原创
go-8
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法