|
|
|
@ -82,7 +82,7 @@ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose bac
|
|
|
|
|
|
|
|
|
|
其中,默认的方式就是 `栈展开`,这意味着 Rust 会回溯栈上数据和函数调用,因此也意味着更多的善后工作,好处是可以给出充分的报错信息和栈调用信息,便于事后的问题复盘。`直接终止`,顾名思义,不清理数据就直接退出程序,善后工作交与操作系统来负责。
|
|
|
|
|
|
|
|
|
|
对于绝大多数用户,使用默认选择是最好的,但是当你关心最终编译出的二进制可执行文件大小时,那么可以尝试去使用直接终止的方式(栈展开方式需要使用debug模式编译,生成的可执行文件较大),例如下面的配置修改 `Cargo.toml` 文件,实现在[`release`](../first-try/cargo.md#手动编译和运行项目)模式下遇到 `panic` 直接终止:
|
|
|
|
|
对于绝大多数用户,使用默认选择是最好的,但是当你关心最终编译出的二进制可执行文件大小时,那么可以尝试去使用直接终止的方式,例如下面的配置修改 `Cargo.toml` 文件,实现在[`release`](../first-try/cargo.md#手动编译和运行项目)模式下遇到 `panic` 直接终止:
|
|
|
|
|
```rust
|
|
|
|
|
[profile.release]
|
|
|
|
|
panic = 'abort'
|
|
|
|
@ -149,8 +149,8 @@ let home: IpAddr = "127.0.0.1".parse().unwrap();
|
|
|
|
|
|
|
|
|
|
当调用 `panic!` 宏时,它会
|
|
|
|
|
1. 格式化 `panic` 信息,然后使用该信息作为参数,调用 `std::panic::panic_any()` 函数
|
|
|
|
|
2. `panic_any` 会检查应用是否使用了 `panic hook`,如果使用了,该 `hook` 函数就会被调用
|
|
|
|
|
3. 当 `hook` 函数返回后,当前的线程就开始进行栈展开:从 `panic_any` 开始,如果寄存器或者栈因为某些原因信息错乱了,那很可能该展开会发生异常,最终线程会直接停止,展开也无法继续进行(这一段从hook开始读不懂了,首先不知道hook是干嘛用的,第四句不知道想表达啥。。。)
|
|
|
|
|
2. `panic_any` 会检查应用是否使用了 `panic hook`,如果使用了,该 `hook` 函数就会被调用(hook是一个钩子函数,是外部代码设置的,用于在panic触发时,执行外部代码所需的功能)
|
|
|
|
|
3. 当 `hook` 函数返回后,当前的线程就开始进行栈展开:从 `panic_any` 开始,如果寄存器或者栈因为某些原因信息错乱了,那很可能该展开会发生异常,最终线程会直接停止,展开也无法继续进行
|
|
|
|
|
4. 展开的过程是一帧一帧的去回溯整个栈,每个帧的数据都会随之被丢弃,但是在展开过程中,你可能会遇到被用户标记为 `catching` 的帧(通过 `std::panic::catch_unwind()` 函数标记),此时用户提供的 `catch` 函数会被调用,展开也随之停止:当然,如果 `catch` 选择在内部调用 `std::panic::resume_unwind()` 函数,则展开还会继续。
|
|
|
|
|
|
|
|
|
|
还有一种情况,在展开过程中,如果展开本身 `panic` 了,那展开线程会终止,展开也随之停止。
|
|
|
|
|