为什么 `Box::new` return 不是 `Option` 或 `Result`?
Why doesn't `Box::new` return an `Option` or `Result`?
我不明白为什么 Box::new
不是 return Option
或 Result
。
分配可能会失败,因为内存不是无限的,或者可能发生其他事情;这种情况下的行为是什么?我找不到任何相关信息。
我发现 Rust 开发人员之间就 liballoc 中的一些低级函数不返回 Option
s 进行了以下交流:PR #14230.
特别是以下部分解释了其背后的一些原因:
huonw:
Hm... shouldn't the lowest level library not be triggering task
failure? Are we planning to have any lower-level libraries returning
Option or something?
亚历克斯克里顿:
I found that it was quite common to want to trigger task failure, much more so than I originally realized. I also found that all contexts have some form or notion of failure, although it's not always task failure.
huonw:
I was thinking from the perspective of task failure not being recoverable at the call site, i.e. a higher level library is free to fail, but the absolute lowest building blocks shouldn't, so that people can handle problems as they wish (even if it's just manually triggering task failure). If liballoc isn't designed to be the lowest level allocation library, failing is fine. (BTW, I think you may've misinterpreted my comment, because I wasn't talking about libcore, just liballoc.)
亚历克斯克里顿:
Oops, sorry! I believe that the core allocator interface (located in liballoc) will be specced to not fail!(), just the primitives on top of them (for example, the box operator).
Perhaps we could extend the box syntax to allow returning Option one day to accommodate this use case, because I'd definitely like to be able to re-use this code!
这是语言设计的决定。您不仅要考虑单个操作的逻辑(例如 Box::new
),还要考虑它将如何影响语言的人体工程学。如果我们用 Return
机制来处理内存分配错误,那么这些错误就会开始到处冒泡。即使该方法 目前 没有在堆上分配任何内存,它也可能会在 将来 上使用它。突然间,实现中的一个简单更改将被卡住,因为您必须更改 API,语义版本控制意味着主要版本。所有这一切都有一点好处,因为在存在交换和内存杀手的情况下,内存不足处理不是非常可靠或有用(通常你应该在内存不足错误之前很久就停止分配内存)。
我看到的一个建议的解决方案是将内存不足视为恐慌,展开并终止相应的任务。
更通用的形式是 内存不足 (OOM) 时该怎么办?
处理OOM有很多困难:
- 正在检测,
- 正在从中恢复(优雅地),
- 将其集成到语言中(优雅地)。
第一个问题是检测它。今天的许多操作系统将默认使用交换 space。在这种情况下,在出现 OOM 情况之前,您的进程实际上已经陷入困境,因为开始使用 swap space 会显着减慢进程。当更高的进程需要更多内存(OOM 杀手)时,其他操作系统将杀死低优先级进程,或者承诺比他们当前拥有的更多内存,希望它不会被使用或在必要时可用(过量使用),等...
第二个问题是恢复。在进程级别,恢复的唯一方法是释放内存......同时不分配任何内存。这并不像听起来那么容易,例如不能保证 panicing 和 unwinding 不需要 allocating 内存(例如,如果不小心,存储 panic 消息的行为可能会分配).这就是为什么当前的 rustc runtime aborts by default on OOM.
第三个问题是语言集成:内存分配无处不在。 Box
、Vec
、String
等的任何使用...因此,如果您避开 panic 路线并改用 Result
路线,您几乎需要调整任何改变方法签名来解决这种失败,这将在所有接口中冒泡。
最后,值得注意的是,在需要处理内存分配失败的领域中...通常 不允许 开始内存分配。例如,在关键的嵌入式软件中,所有内存都是预先分配的,并且有一个证明不需要超过分配的内存。
这很重要,因为这意味着 极少数 情况下 (1) 允许动态内存分配,并且 (2) 其失败必须由进程妥善处理本身。
在这一点上,人们只能想知道应该在这上面花费多少复杂性预算,以及这会给 99% 的程序带来多少复杂性关心
对于2021年过来的人,linus和你有同样的担忧。
I do think that the "run-time failure panic" is a fundamental issue.
希望通过 Rust Team Effects 解决这个问题。
https://github.com/rust-lang/rust/pull/84266
我不明白为什么 Box::new
不是 return Option
或 Result
。
分配可能会失败,因为内存不是无限的,或者可能发生其他事情;这种情况下的行为是什么?我找不到任何相关信息。
我发现 Rust 开发人员之间就 liballoc 中的一些低级函数不返回 Option
s 进行了以下交流:PR #14230.
特别是以下部分解释了其背后的一些原因:
huonw:
Hm... shouldn't the lowest level library not be triggering task failure? Are we planning to have any lower-level libraries returning Option or something?
亚历克斯克里顿:
I found that it was quite common to want to trigger task failure, much more so than I originally realized. I also found that all contexts have some form or notion of failure, although it's not always task failure.
huonw:
I was thinking from the perspective of task failure not being recoverable at the call site, i.e. a higher level library is free to fail, but the absolute lowest building blocks shouldn't, so that people can handle problems as they wish (even if it's just manually triggering task failure). If liballoc isn't designed to be the lowest level allocation library, failing is fine. (BTW, I think you may've misinterpreted my comment, because I wasn't talking about libcore, just liballoc.)
亚历克斯克里顿:
Oops, sorry! I believe that the core allocator interface (located in liballoc) will be specced to not fail!(), just the primitives on top of them (for example, the box operator).
Perhaps we could extend the box syntax to allow returning Option one day to accommodate this use case, because I'd definitely like to be able to re-use this code!
这是语言设计的决定。您不仅要考虑单个操作的逻辑(例如 Box::new
),还要考虑它将如何影响语言的人体工程学。如果我们用 Return
机制来处理内存分配错误,那么这些错误就会开始到处冒泡。即使该方法 目前 没有在堆上分配任何内存,它也可能会在 将来 上使用它。突然间,实现中的一个简单更改将被卡住,因为您必须更改 API,语义版本控制意味着主要版本。所有这一切都有一点好处,因为在存在交换和内存杀手的情况下,内存不足处理不是非常可靠或有用(通常你应该在内存不足错误之前很久就停止分配内存)。
我看到的一个建议的解决方案是将内存不足视为恐慌,展开并终止相应的任务。
更通用的形式是 内存不足 (OOM) 时该怎么办?
处理OOM有很多困难:
- 正在检测,
- 正在从中恢复(优雅地),
- 将其集成到语言中(优雅地)。
第一个问题是检测它。今天的许多操作系统将默认使用交换 space。在这种情况下,在出现 OOM 情况之前,您的进程实际上已经陷入困境,因为开始使用 swap space 会显着减慢进程。当更高的进程需要更多内存(OOM 杀手)时,其他操作系统将杀死低优先级进程,或者承诺比他们当前拥有的更多内存,希望它不会被使用或在必要时可用(过量使用),等...
第二个问题是恢复。在进程级别,恢复的唯一方法是释放内存......同时不分配任何内存。这并不像听起来那么容易,例如不能保证 panicing 和 unwinding 不需要 allocating 内存(例如,如果不小心,存储 panic 消息的行为可能会分配).这就是为什么当前的 rustc runtime aborts by default on OOM.
第三个问题是语言集成:内存分配无处不在。 Box
、Vec
、String
等的任何使用...因此,如果您避开 panic 路线并改用 Result
路线,您几乎需要调整任何改变方法签名来解决这种失败,这将在所有接口中冒泡。
最后,值得注意的是,在需要处理内存分配失败的领域中...通常 不允许 开始内存分配。例如,在关键的嵌入式软件中,所有内存都是预先分配的,并且有一个证明不需要超过分配的内存。
这很重要,因为这意味着 极少数 情况下 (1) 允许动态内存分配,并且 (2) 其失败必须由进程妥善处理本身。
在这一点上,人们只能想知道应该在这上面花费多少复杂性预算,以及这会给 99% 的程序带来多少复杂性关心
对于2021年过来的人,linus和你有同样的担忧。
I do think that the "run-time failure panic" is a fundamental issue.
希望通过 Rust Team Effects 解决这个问题。
https://github.com/rust-lang/rust/pull/84266