美文网首页
golang无法捕获的异常之fatal error

golang无法捕获的异常之fatal error

作者: 小易哥学呀学 | 来源:发表于2021-12-12 21:08 被阅读0次

panic是panic

fatal是fatal

先看一段重复Unlock的例子

package main

import (
    "fmt"
    "sync"
)

func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("打印错误:",err) // 捕获并打印

        }
    }()

    l := sync.Mutex{}

    l.Lock()

    l.Unlock()
    l.Unlock() // 重复解锁
}

输出

fatal error: sync: unlock of unlocked mutex

可见defer+recover是无法捕获fatal error地,我们的打印没有执行。为啥呢,一步步来~

首先,让我们全局搜索一下sync: unlock of unlocked mutex,发现了这段文案的出处。

// path: /usr/local/go/src/sync/mutex.go:196
func (m *Mutex) unlockSlow(new int32) {
    if (new+mutexLocked)&mutexLocked == 0 {
        throw("sync: unlock of unlocked mutex") // 错误文案在这里
    }
...忽略部分...

但是我们发现并没有错误前缀fatal error:

继续查看throw()函数,我们发现了错误前缀fatal error:

// path: /usr/local/go/src/runtime/panic.go:1188
func throw(s string) {
    // Everything throw does should be recursively nosplit so it
    // can be called even when it's unsafe to grow the stack.
    // 把错误加入到系统调用栈中
    systemstack(func() {
        print("fatal error: ", s, "\n")
    })
    ...忽略部分...
    fatalthrow()
    *(*int)(nil) = 0 // not reached 这一段是为了保险起见,让进程能退出。
}

再继续查看fatalthrow()

// path: /usr/local/go/src/runtime/panic.go:1244
func fatalthrow() {
    ...忽略部分...
    systemstack(func() {
        ...忽略部分...
        exit(2) // 关键,进程直接退出。
    })

    *(*int)(nil) = 0 // not reached 这一段是为了保险起见,让进程能退出。
}

无法捕获的原因就在于这个exit(2)函数了 。
exit(2):执行该函数会直接退出进程,所以我们的defer+recover无法执行了。

总结

throw()函数会打印调用栈信息,然后直接终止整个进程!
想知道其他fatal error,全局搜索throw()函数,看都有哪些地方调用即可。

出个面试题:go都有哪些异常捕获不住?

本文属于原创,首发于微信公众号【小易哥学呀学】,如需转载请后台留言。
加微信入Golang交流群。vx:17610015120

相关文章

网友评论

      本文标题:golang无法捕获的异常之fatal error

      本文链接:https://www.haomeiwen.com/subject/yelrfrtx.html