Go中是否可以恢复所有运行时错误?

chr*_*and 8 go

我认为一个等效的问题是-是否所有运行时错误都可能致命,恐慌?因为任何恐慌都应该可以恢复。我不是在谈论从诸如os.Exit(),或log.Fatal(),Go运行时中的错误或某人通过电源线跳闸中恢复,而是从其他运行时错误中恢复,这将导致程序崩溃。

这是可以通过紧急/恢复捕获的运行时错误的示例:

package main

import (
    "fmt"
)

func errorHandler() {
    r := recover()
    err := r.(error)
    if err == nil {
        return
    }
    fmt.Println(err.Error())
}

func foo() {
    defer errorHandler()
    smallSlice := []int{1, 0, 1}
    smallSlice[10] = 1
}

func main() {
    foo()
    fmt.Println("recovery, end of main")
}
Run Code Online (Sandbox Code Playgroud)

输出:

运行时错误:索引超出范围
恢复,主程序结束

是否有一些示例,其中运行时错误将使程序崩溃而没有可恢复的恐慌?

pet*_*rSO 8

是否有一些示例,其中运行时错误将使程序崩溃而没有可恢复的恐慌?


例如,内存不足(OOM)错误不可恢复。


src/runtime/panic.go

// fatalpanic implements an unrecoverable panic. It is like fatalthrow, except
// that if msgs != nil, fatalpanic also prints panic messages and decrements
// runningPanicDefers once main is blocked from exiting.
func fatalpanic(msgs *_panic) {
    // ...
}

// fatalthrow implements an unrecoverable runtime throw. It freezes the
// system, prints stack traces starting from its caller, and terminates the
// process.
func fatalthrow() {
    // ...
}
Run Code Online (Sandbox Code Playgroud)


icz*_*cza 6

首先更改您的errorHandler()原因,因为如果没有紧急情况,r将会发生nil,因此类型断言将失败:

func errorHandler() {
    if r := recover(); r != nil {
        fmt.Println(r)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这里是一些带有代码的示例,这些代码会产生无法恢复的运行时错误:

1.内存不足:

func foo() {
    defer errorHandler()
    _ = make([]int64, 1<<40) // You have to change the size on 32-bit systems
}
Run Code Online (Sandbox Code Playgroud)

2.并发映射读写

有关详细信息,请参见如何从并发映射写入中恢复?,例如,请参见能否将map [string] string编组到json会返回错误?

func foo() {
    defer errorHandler()
    m := map[string]int{}

    go func() {
        for {
            m["x"] = 1
        }
    }()
    for {
        _ = m["x"]
    }
}
Run Code Online (Sandbox Code Playgroud)

3.堆栈内存耗尽

有关详细信息,请参阅Go是否具有等效的“无限调用堆栈”?

func foo() {
    defer errorHandler()

    var f func(a [1000]int64)
    f = func(a [1000]int64) {
        f(a)
    }
    f([1000]int64{})
}
Run Code Online (Sandbox Code Playgroud)

4.尝试将nil函数作为goroutine 启动

func foo() {
    defer errorHandler()
    var f func()
    go f()
}
Run Code Online (Sandbox Code Playgroud)

5.所有goroutine都在睡眠中-死锁

标题说明了一切。这是阻止当前goroutine的简单代码,但是,如果您启动了其他goroutine,则显然不会遇到崩溃。在此处查看其他示例:永远进入项目的主要goroutine睡眠状态吗?

func foo() {
    defer errorHandler()
    select {}
}
Run Code Online (Sandbox Code Playgroud)

6.线程限制用尽

如果您的goroutine被IO操作阻塞,则可能会启动新线程来执行其他goroutine。最大线程数显然有一个限制,如果达到最大线程数,您的应用将崩溃。

  • 我们可以在这里,在运行时包中有很多`throw()`,数据竞赛真的可以为您带来任何好处。常规的SIGSEGV(没有debug.SetPanicOnFault),sync:解锁的互斥锁解锁,互斥状态不一致,分配太大,所有throw()都掉到了我的头顶。 (4认同)