【译】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这样的程序,而是要实现一定的功能,具备一定实用价值的程序),在编 ...
随机推荐
- shell中 -eq,-ne,-gt,-lt,-ge,-le数字比较符
使用说明: -eq //equals等于 -ne //no equals不等于 -gt //greater than 大于 -lt //less than小于 -ge ...
- canal 实现Mysql到Elasticsearch实时增量同步
简介: MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据 ...
- 在 Ubuntu 上安装 .NET SDK 或 .NET 运行时
在wsl Ubuntu 20.04上面安装dotnet链接 https://docs.microsoft.com/zh-cn/dotnet/core/install/linux-ubuntu Ubun ...
- 【greys使用】阿里greys在线诊断工具
Greys是一个Java进程的异常诊断工具,可以在不停止程序的前提下,对一些问题进行检测.这个框架主要是采用Java的探针技术,可以做到动态修改java的字节码技术.前提是Jdk版本6+.(prema ...
- Python+Selenium学习笔记2 - 字符串
跟着网络课程学了几个小程序. 1.判断a字符串是否为b字符串的子串 1 # coding = utf-8 2 3 # 判断str_a字符串是否为str_b字符串的子串 4 5 str_a = &quo ...
- LLD-LLVM链接器
LLD-LLVM链接器 LLD是LLVM项目中的链接器,是系统链接器的直接替代,并且运行速度比它们快得多.它还提供了对工具链开发人员有用的功能. 链接器按完整性降序支持ELF(Unix),PE / C ...
- TcaplusDB祝大家端午安康!
"五月五,端午到,赛龙舟,真热闹.吃粽子,带香包,蚊虫不来身边闹."这首脍炙人口.描绘着端午节风俗的儿歌,想必大家都听过. 每年的农历五月初五,是我国四大传统节日(春节.清明节.端 ...
- redis常用命令练习
redis-server redis-cli select 0-15 redis key: string\hash\list\set\sortedset 1.增删改查... keys * 所有key ...
- .NET平台系列24:从.NET Framework迁移到.NET Core/.NET5的技术指南
系列目录 [已更新最新开发文章,点击查看详细] 本文讲解了在将代码从 .NET Framework 移植到 .NET(旧称为 .NET Core)时应考虑的事项. 对于许多项目,从 .NET ...
- P5960 【模板】差分约束算法
题目描述 给出一组包含 $m$ 个不等式,有 $n$ 个未知数的形如: 的不等式组,求任意一组满足这个不等式组的解. 输入格式 第一行为两个正整数 $n,m$,代表未知数的数量和不等式的数量. 接下来 ...