【译】Go:程序如何恢复?
原文:https://medium.com/a-journey-with-go/go-how-does-a-program-recover-fbbbf27cc31e
当程序不能正确处理错误时, 会触发 Go 的 panic,比如无效的内存访问。如果错误时意外发生的,并且没有别的方法来处理它,开发人员也可以触发 panic。理解恢复或终止的流程有助于理解程序 panic 的后果。
多个函数帧
关于 panic 和 recover 有很多典型的例子和文档,包括 Go 博客中的 "Defer, Panic, and Recover"。让我们关注一个不同的例子,其中 panic 涉及到多个 defer 函数。下面是例子:
func main() {
defer println("defer 1")
level1()
}
func level1() {
defer println("defer func 3")
defer func() {
if err := recover(); err != nil {
println("recovering in progress...")
}
}()
defer println("defer 2")
level2()
}
func level2() {
defer println("defer func 4")
panic("foo")
}
这个程序由三个函数组成, 它们在链中被调用。一旦代码在最后一层 panic,Go将在主函数中运行这些 defer 函数:

在该阶段的中运行的代码没有恢复 panic, 然后 Go 构建父函数并且调用每个函数里的 defer

提醒一下,defer 函数是按照 后进先出(LIFO)的顺序执行的。关于 defer 函数内部信息,我建议你阅读 Go: How Does defer Statement Work?
由于一个其中一个函数可以恢复 panic,所以 Go 需要一种方法来跟踪它并恢复程序的执行。为此,每个 goroutine 都嵌入了一个特殊的属性,指向了代表 panic 的对象

当 panic 发生时,在运行 defer 函数之前创建该对象。然后,恢复 panic 的函数实际上只是返回该对象的信息,并将 panic 标记为已恢复

一旦发现 panic 已经恢复,Go需要继续当前的工作。然而,由于运行时是在 defer 中, 它不知道从哪里恢复,因此,当 panic 被标记为已恢复时,Go保存当前函数的程序计数器和堆栈指针,以便在发生 panic 之后恢复。

我们也可以用 objdump 检查程序计数器代表什么
(e.g. objdump -D my-binary | grep 105acef)

此指令指向函数调用 runtime.deferreturn, 这是由编译器插入到每个函数末尾的指令,该指令运行 deferred 函数。在前面的例子中,它们中的大多数在恢复之前已经运行,因此在返回到调用者之前只有还没被调用的。
Wait Group
理解这个工作流向我们展示了defer函数的重要性,以及如何发挥作用,例如,在处理一组 goroutine 时,在 defer 函数中延迟对 WaitGroup 对象的调用可以防止死锁,这里有一个例子:
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer func() {
if err := recover(); err != nil {
println(err.(string))
}
}()
p()
wg.Done()
}()
wg.Wait()
}
func p() {
panic("foo")
}
这个程序会导致死锁,因为 wg.Done 永远不会被调用。将 wg.Done 移动到一个 defer 函数可以确保被调用,程序可以继续执行
Goexit
值得注意的是函数 runtime.Goexit 使用完全相同的工作流。它实际上创建了一个带有特殊标志的 panic 对象,以区别真正的 panic。此标志允许运行时跳过恢复并正确退出,而不是停止程序的执行。
【译】Go:程序如何恢复?的更多相关文章
- [译]好程序员的五声“呐喊”
通常编程情况下,会导致软件项目变坏的一些列反应 原文:The five shouts of good programmers 在任何一天,在这个世界上都有软件项目正在失败,这很常见.常见到当软件产品按 ...
- python学习笔记:"爬虫+有道词典"实现一个简单的英译汉程序
1.有道的翻译 网页:www.youdao.com Fig1 Fig2 Fig3 Fig4 再次点击"自动翻译"->选中'Network'->选中'第一项',如下: F ...
- eclipse代码恢复(开发程序代码恢复)
如果误操作,让本地代码丢失了不用怕,Eclipse local history可以恢复. 误删除文件后,直接ctrl+z可以恢复. 拉去代码覆盖了本地,也可以一个一个或者整体进行恢复:http://b ...
- [译]Java 程序员应该了解的 10 个面向对象设计原则
面向对象设计原则是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心,但大多数Java程序员追逐像Singleton.Decorator ...
- Ionic1 环境破坏后程序重新恢复过程
ionic platform remove android ionic platform add android cordova plugin add cordova-plugin-network-i ...
- Android清单文件详解(三)----应用程序的根节点<application>
<application>节点是AndroidManifest.xml文件中必须持有的一个节点,它包含在<manifest>节点下.通过<application>节 ...
- 如何定位Release 版本中程序崩溃的位置 ---利用map文件 拦截windows崩溃函数
1 案例描述 作为Windows程序员,平时最担心见到的事情可能就是程序发生了崩溃(异常),这时Windows会提示该程序执行了非法操作,即将关闭.请与您的供应商联系.呵呵,这句微软的“名 ...
- 小白学phoneGap《构建跨平台APP:phoneGap移动应用实战》连载四(使用程序载入事件)
在了解了PhoneGap中都有哪些事件之后,本节将開始对这些事件的使用方法进行具体地介绍.本节要介绍的是程序载入事件,也就是deviceready.pause和resume这3个事件. [范例4-2 ...
- java程序错误类型及异常处理
一.程序的错误类型 在程序设计中,无论规模是大是小,错误总是难免的.程序的设计很少有能够一次完成,没有错误的(不是指HelloWorld这样的程序,而是要实现一定的功能,具备一定实用价值的程序),在编 ...
随机推荐
- mitogen附带文件到远程主机
#!/usr/bin/env python # import mitogen.master import mitogen.select import subprocess import logging ...
- Linux_网络基础管理
一.网卡的命名 1.传统网卡命名 eth0.eth1.eth2.eth3......... wlan0.wlan1.waln2.wlan3......... 2.RHEL7命名机制 systemd对网 ...
- ZooKeeper IDEA 可视化管理插件安装
1. 安装 zookeeper 插件 打开 IDEA->Settings->Plugins,然后在 Marketplace 输入 "zookeeper" 如下: 插件安 ...
- Java 中 volatile 关键字及其作用
引言 作为 Java 初学者,几乎从未使用过 volatile 关键字.但是,在面试过程中,volatile 关键字以及其作用还是经常被面试官问及.这里给各位童靴讲解一下 volatile 关键字的作 ...
- mysql基础之mariadb库管理和表管理语句
一.数据库管理语句 1.Syntax: CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ... cr ...
- 简单读读源码 - dubbo多提供者(provider)配置方法
简单读读源码 - dubbo多提供者(provider)配置方法 消费者端dubbo的yml配置 dubbo: consumer: timeout: 300000 protocol: name: du ...
- 防火墙 firewall iptables
firewalld FirewallD 使用服务service 和区域zone来代替 iptables 的规则rule和链chain,默认情况下,有以下的区域zone可用: drop – 丢弃所有传入 ...
- Day029 JDK8中新日期和时间API (四)
JDK8中新日期和时间API 其他的一些API ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris ZonedDateTime:一个在ISO-8601日历系统时区的 ...
- 【Web前端HTML5&CSS3】12-字体
笔记来源:尚硅谷Web前端HTML5&CSS3初学者零基础入门全套完整版 目录 字体 1. 字体相关的样式 2. font-family 3. 几种字体 手写体 艺术体 乱码字体 中文字体 4 ...
- JS 反射机制及 Reflect 详解
一.什么是反射机制 反射机制是在编译阶段不知道是哪个类被加载,而是在运行的时候才加载.执行. 也就是说,反射机制指的是程序在运行时能够获取自身的信息. js 中的 apply 就是反射机制. 二.Re ...