为什么Rust认为泄漏内存是安全的?

13
根据Rust Book中的这一章节,通过创建指针循环,可能会导致内存泄漏:
Rust的内存安全保证使得意外创建永远不会被清理的内存(称为内存泄漏)变得困难,但并非不可能。与在编译时禁止数据竞争相同,完全防止内存泄漏不是Rust所保证的,这意味着在Rust中内存泄漏是内存安全的。我们可以使用Rc<T>RefCell<T>来查看Rust允许内存泄漏:可以创建引用,其中项彼此引用形成循环。这会导致内存泄漏,因为循环中每个项目的引用计数永远不会达到0,并且值永远不会被删除。
存在替代方案,例如“弱指针”,可以创建自引用结构,但在删除时仍然可以清除它们。实际上,在该章节后面建议使用Weak<T>
为什么Rust认为这是安全的?为什么这是一种语言没有做任何事情防止“糟糕的程序员行为”的情况?

你为什么认为这样做是不安全的?它是否违反了Rust提供的任何保证?它是否以任何方式影响控制流程?以后是否可能以任何方式访问遗忘的字节? :) - hellow
1
除了你已经引用的书中的部分,我认为关于这个问题没有什么可说的了。"内存泄漏是内存安全的"才是正确答案。 - E net4
1
@hellow 这就是问题所在:我本来以为“遗忘”(将东西保留在内存中“永远”而不运行其析构函数)是不可取的,但令我惊讶的是,事实上 Rust 的保证并没有涉及到这种情况,这也是我提出这个问题的原因。 - Qqwy
1个回答

22

因为它是安全的。


unsafe 在 Rust 中具有非常具体的含义,它专门针对触发 未定义行为 的编程错误。这些是最严重的错误,因为它们完全颠覆了你对程序的整体理解,允许编译器或硬件以不可预测的方式行事。

内存泄漏不会触发 未定义行为,因此是安全的。

您可能会对Nomicon(Rust Book 的 Unsafe 版本)对泄漏的解释感兴趣;关于 ScopeGuard 的示例通常被称为 Leakpocalypse。


值得注意的是,垃圾回收语言很容易泄漏内存,例如,将键值对添加到 Map 中而从未删除将最终导致堆耗尽;而垃圾回收不能阻止它。

一个不断增长的 Map 与反复忘记释放指针一样令人不满,但GC语言通常被认为是安全的。


很棒的答案!Nomicon比我预期的对这个问题的回答更深入 :')。然而,我认为“不断增长的Map”可能不是最好的例子,因为虽然这可能会在某些时候耗尽可用内存,但它并没有“泄漏”它(一旦程序停止使用地图,无论它变得多么大,它都将被GC回收)。两个实例(Map和不可访问的指针)都将在某个时候触发堆耗尽,这绝对是有趣的... - Qqwy
我猜“堆耗尽”是我们在物理冯·诺依曼机器达到模拟图灵机的极限时遇到的实际问题(毕竟,图灵机具有无限的内存),这意味着堆耗尽在实践中是一个严重的问题,但在理论上是安全的,因为它不可能发生? - Qqwy
1
@Qqwy: (1) 关于程序停止使用映射时Map内存被回收的问题,我想指出大多数操作系统在程序停止时也会收集进程的内存。从这个意义上说,泄漏总是短暂的。(2) 我喜欢你对理论(无限内存)和实践(有限内存)的描述。 - Matthieu M.
1
请注意,内存泄漏可能会被声明为未定义行为(例如使用线性类型)。也就是说,开发Rust的人可以定义语言中的UB是什么。因此,请确保您不要说“内存泄漏不会导致未定义行为,因为它们是安全的”,因为这将是一个循环定义。 - Centril

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接