为什么"Box::new"不返回"选项"或"结果"?



我不明白为什么Box::new不返回OptionResult

分配可能会失败,因为内存不是无限的,或者可能会发生其他事情;在这种情况下的行为是什么?我找不到有关它的任何信息。

更一般的形式是 在内存不足 (OOM) 上做什么?

处理 OOM 存在许多困难:

  • 检测到它,
  • 从中恢复(优雅),
  • 将其集成到语言中(优雅地)。

第一个问题是检测它。默认情况下,今天的许多操作系统将使用交换空间。在这种情况下,您的进程实际上在进入 OOM 情况之前就遇到了麻烦,因为开始使用交换空间会显着减慢进程速度。当更高的进程需要更多内存时,其他操作系统会杀死低优先级进程(OOM killer),或者承诺比当前拥有的内存更多,希望它不会被使用或在必要时可用(过度提交),等等......

第二个问题是恢复。在进程级别,恢复的唯一方法是释放内存...同时没有分配任何内容。这并不像听起来那么容易,例如,不能保证恐慌和展开不需要分配内存(例如,如果不小心,存储恐慌消息的行为可能会分配)。这就是为什么当前的 rustc 运行时默认在OOM 上中止的原因。

第三个问题是语言集成:内存分配无处不在。任何使用BoxVecString等...因此,如果您避开 panic 路由并改用Result路由,则需要调整几乎任何突变方法签名以解决此类故障,这将在所有接口中冒泡。

最后,值得注意的是,在需要处理内存分配故障的域中......通常不允许开始分配内存。例如,在关键的嵌入式软件中,所有内存都是预先分配的,并且有证据表明所需的内存不超过分配的内存。

这很重要,因为这意味着在极少数情况下 (1) 允许动态内存分配和 (2) 其故障必须由进程本身优雅地处理。

在这一点上,人们只能想知道应该为此花费多少复杂性预算,以及这将给99%不关心的程序带来多少复杂性

我发现 Rust 开发人员之间关于 liballoc 中的一些较低级别函数不返回Options 的以下通信:PR #14230。

特别是以下部分解释了它背后的一些原因:

浑浑:

嗯......最低级别的库不应该触发任务 失败?我们是否计划让任何较低级别的库返回 选项什么的?

亚历克斯克莱顿

发现想要触发任务失败是很常见的,比我最初意识到的要多得多。我还发现,所有上下文都有某种形式的失败或失败概念,尽管并不总是任务失败。

浑浑:

我是从任务失败在调用站点无法恢复的角度思考的,即更高级别的库可以自由失败,但绝对最低的构建块不应该失败,以便人们可以随心所欲地处理问题(即使它只是手动触发任务失败)。如果 liballoc 不是设计为最低级别的分配库,那么失败是可以的。(顺便说一句,我想你可能误解了我的评论,因为我不是在谈论libcore,只是liballoc。

亚历克斯克莱顿

哎呀,对不起!我相信核心分配器接口(位于liballoc)不会被指定为不会失败!(),只是它们顶部的基元(例如,框运算符)。

也许我们可以扩展 box 语法以允许有一天返回 Option 以适应这个用例,因为我绝对希望能够重用这段代码!

这是一个语言设计决策。你不仅要考虑单个操作的逻辑(例如Box::new),还要考虑它将如何影响语言人体工程学。如果我们使用Return机制来处理内存分配错误,那么这些错误就会开始在任何地方冒泡。即使该方法当前未在堆上分配任何内存,将来也可能会求助于它。突然之间,实现中的简单更改将卡住,因为您必须更改API,这对于语义版本控制意味着主要版本。所有这些都有一点好处,因为在存在交换和内存杀手的情况下,内存不足处理不是很可靠或有用(通常您应该在出现内存不足错误之前很久就停止分配内存)。

这个话题在reddit上得到了很多讨论。

我看到的一个建议的解决方案是将内存不足视为恐慌,展开并终止相应的任务。

对于来自 2021 年的人来说,linus 对你有同样的担忧。

我确实认为"运行时故障恐慌"是一个基本问题。

希望这将通过 rust 团队效果来解决。

https://github.com/rust-lang/rust/pull/84266

https://lwn.net/ml/linux-kernel/YHdSATy9am21Tj4Z@localhost/

https://lkml.org/lkml/2021/4/14/1099

最新更新