go panic的那点“破“事

       go panic和c++ coredump差不多, 来看看go panic.

 

       看程序:

package main 
import "fmt" 

func main() {
	fmt.Println("main begin")
	var p *int
	*p = 0
	fmt.Println("main end")

	for {}
}

       结果:

main begin
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1090f33]

goroutine 1 [running]:
main.main()
        /Users/xxx/test/a.go:7 +0x63
exit status 2

      可见,panic后,进程退出了。

 

      再看:

package main 
import "fmt" 
import "runtime/debug"

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("haha")
			debug.PrintStack()
		}
	}()


	fmt.Println("main begin")
	var p *int
	*p = 0
	fmt.Println("main end")

	for {}
}

      结果:

main begin
haha
goroutine 1 [running]:
runtime/debug.Stack(0xc00000c018, 0xc000076de8, 0x1)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.main.func1()
        /Users/xxx/test/a.go:9 +0x82
panic(0x10a9620, 0x115d520)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.main()
        /Users/xxx/test/a.go:16 +0x83

       进程还是退出了,可见在main中recover并没有什么卵用。

 

       再看:

package main 
import "fmt" 
import "runtime/debug"

func fun() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("haha")
			debug.PrintStack()
		}
	}()
	
	fmt.Println("fun begin")
	var p *int
	*p = 0
	fmt.Println("fun end")
}


func main() {
	fmt.Println("main begin")
	fun()
	fmt.Println("main end")
	for {}
}

        结果:

main begin
fun begin
haha
goroutine 1 [running]:
runtime/debug.Stack(0xc00008c008, 0xc000082d88, 0x1)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
        /Users/xxx/test/a.go:9 +0x82
panic(0x10a96e0, 0x115d520)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.fun()
        /Users/xxx/test/a.go:15 +0x83
main.main()
        /Users/xxx/test/a.go:22 +0x66
main end

     可见,在fun层panic后退出了,没有被for{}卡住,但在main层没有退出,被for{}卡住了, 进程还是活着的。

     

     那好,现在来看看:

package main 
import "fmt" 
import "runtime/debug" 

func high() {
	fmt.Println("high begin")
	middle()
	fmt.Println("high end")
}

func middle() {
	fmt.Println("middle begin")
	low()
	var p *int
	*p = 0
	fmt.Println("middle end")
}

func low() {
	fmt.Println("low begin")
	fmt.Println("low end")
}

func fun() {
    fmt.Println("fun begin")

	defer func() {
		debug.PrintStack()
	}()

	fmt.Println("yyy")
	high()
	fmt.Println("zzz")

	fmt.Println("fun end")

	for {}
}

func main() {
	fmt.Println("main begin")
	fun()
	a := 2
	b := 3
	fmt.Println("main end", a * b)

	for {}
}

       结果:

main begin
fun begin
yyy
high begin
middle begin
low begin
low end
goroutine 1 [running]:
runtime/debug.Stack(0x0, 0x10, 0x8)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
        /Users/xxx/test/a.go:28 +0x20
panic(0x10a9a00, 0x115e520)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.middle()
        /Users/xxx/test/a.go:15 +0x68
main.high()
        /Users/xxx/test/a.go:7 +0x66
main.fun()
        /Users/xxx/test/a.go:32 +0xc6
main.main()
        /Users/xxx/test/a.go:42 +0x66
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1091528]

goroutine 1 [running]:
main.middle()
        /Users/xxx/test/a.go:15 +0x68
main.high()
        /Users/xxx/test/a.go:7 +0x66
main.fun()
        /Users/xxx/test/a.go:32 +0xc6
main.main()
        /Users/xxx/test/a.go:42 +0x66
exit status 2

      很显然,没有recover去处理panic信息,所以整个进程崩溃, 如下:

 

      再来看看:

package main 
import "fmt" 
import "runtime/debug" 

func high() {
	fmt.Println("high begin")
	middle()
	fmt.Println("high end")
}

func middle() {
	fmt.Println("middle begin")
	low()
	var p *int
	*p = 0
	fmt.Println("middle end")
}

func low() {
	fmt.Println("low begin")
	fmt.Println("low end")
}

func fun() {
    fmt.Println("fun begin")

	defer func() {
		if err := recover(); err != nil {
			debug.PrintStack()
		}
	}()

	fmt.Println("yyy")
	high()
	fmt.Println("zzz")

	fmt.Println("fun end")

	for {}
}

func main() {
	fmt.Println("main begin")
	fun()
	a := 2
	b := 3
	fmt.Println("main end", a * b)

	for {}
}

        结果:

main begin
fun begin
yyy
high begin
middle begin
low begin
low end
goroutine 1 [running]:
runtime/debug.Stack(0x115e5c0, 0xc000042c00, 0x0)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
        /Users/xxx/test/a.go:29 +0x42
panic(0x10a9a20, 0x115e520)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.middle()
        /Users/xxx/test/a.go:15 +0x68
main.high()
        /Users/xxx/test/a.go:7 +0x66
main.fun()
        /Users/xxx/test/a.go:34 +0xc6
main.main()
        /Users/xxx/test/a.go:44 +0x66
main end 6

      可以看到middle层有panic,  故提前异常退出middle, high和fun,  但在fun层被recover了,所以main层仍然正常,整个进程不会崩溃,仍然活得好好的。

 

     最后看看,如何获取堆栈信息的串呢? 且看:

package main 
import "fmt" 
import "runtime/debug" 

func fun() {
    fmt.Println("fun begin")

	defer func() {
		if err := recover(); err != nil {
			debug.PrintStack()
			fmt.Println("xxx", string(debug.Stack()))
		}
	}()

	var p *int
	*p = 0
	fmt.Println("fun end")

	for {}
}

func main() {
	fmt.Println("main begin")
	fun()
	fmt.Println("main end")

	for {}
}

        结果:

main begin
fun begin
goroutine 1 [running]:
runtime/debug.Stack(0xc000088060, 0xc00009a000, 0xa)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
        /Users/xxx/test/a.go:10 +0x46
panic(0x10a9760, 0x115d520)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.fun()
        /Users/xxx/test/a.go:16 +0x7f
main.main()
        /Users/xxx/test/a.go:24 +0x66
xxx goroutine 1 [running]:
runtime/debug.Stack(0xc00007ada8, 0x10a9760, 0x115d520)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
main.fun.func1()
        /Users/xxx/test/a.go:11 +0x4b
panic(0x10a9760, 0x115d520)
        /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.fun()
        /Users/xxx/test/a.go:16 +0x7f
main.main()
        /Users/xxx/test/a.go:24 +0x66

main end

   

     总之,panic触发层到recover层都会异常退出。 但recover层之上不会异常退出。

 

     不多说。

 

 

      

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值