为啥 Rust 认为泄漏内存是安全的?
Posted
技术标签:
【中文标题】为啥 Rust 认为泄漏内存是安全的?【英文标题】:Why does Rust consider it safe to leak memory?为什么 Rust 认为泄漏内存是安全的? 【发布时间】:2019-09-30 02:49:20 【问题描述】:根据this chapter in the Rust Book,有可能通过创建指针循环来泄漏内存:
Rust 的内存安全保证使得意外创建从未清理过的内存(称为内存泄漏)变得困难,但并非不可能。完全防止内存泄漏并不是 Rust 的保证之一,就像在编译时不允许数据竞争一样,这意味着内存泄漏在 Rust 中是内存安全的。我们可以看到 Rust 通过使用
Rc<T>
和RefCell<T>
允许内存泄漏:可以创建引用,其中项目在循环中相互引用。这会造成内存泄漏,因为循环中每个项目的引用计数永远不会达到 0,并且值永远不会被丢弃。
存在诸如“弱指针”之类的替代方案,可让您创建自引用结构,在删除时仍可清理这些结构。事实上,使用Weak<T>
实际上是在那一章后面提出的。
为什么 Rust 认为这是安全的?为什么这是一个语言没有做任何事情来防止“不良程序员行为”的例子?
【问题讨论】:
您为什么认为这样做不安全?它会破坏 Rust 提供的任何保证吗?它是否以任何方式影响控制流?以后可以以任何方式访问被遗忘的字节吗? :) 除了你已经引用的那本书的部分,我认为这方面没什么可说的。 “内存泄漏是内存安全的” 是正确的答案。 @hellow 事情就是这样:我曾预料到“忘记”东西(将事物“永远”保存在内存中而不运行它们的析构函数)是不可取的,我惊讶地发现确实是 Rust 的保证不说这种情况,这也是我问这个问题的原因。 【参考方案1】:因为它是安全的。
unsafe
在 Rust 中具有非常特殊的含义,它专门针对触发未定义行为的编程错误类。这些是最严重的错误,因为它们完全颠覆了您对程序的整体理解,导致编译器或硬件以不可预知的方式运行。
内存泄漏不会触发未定义行为,因此是安全的。
您可能对 Nomicon(Rust Book 的 Unsafe 等价物)对Leaking 的评价感兴趣;关于ScopeGuard
的例子通常被称为泄漏启示录。
值得注意的是,垃圾收集语言很容易泄漏内存,例如。一个简单的Map
,其中添加了键值对而从未被删除,最终将导致堆耗尽;并且 GC 将无法阻止它。
不断增长的Map
与反复忘记free
指针一样不可取,在任何一种情况下,堆耗尽都迫在眉睫,但通常认为经过 GC 处理的语言是安全的。
【讨论】:
很好的答案! Nomicon 比我预期的这个问题的答案更深入:')。我确实认为“不断增长的Map
”可能不是最好的例子,但是,因为虽然这可能会在某个时候耗尽可用内存,但它并没有“泄漏”它(尽快当程序停止使用地图时,无论它有多大,它都会被 GC 回收)。事实上,这两个实例(Map
和无法访问的指针)都会在某个时候触发堆耗尽,这绝对很有趣......
我猜“堆耗尽”是我们遇到的一个实际问题,当我们的物理冯诺依曼机器在其模拟图灵机的能力极限时(毕竟,它有无限的内存),这意味着堆耗尽在实践中是一个糟糕的问题,但它是安全的在理论上因为它不可能发生?
@Qqwy:(1)关于Map
程序停止使用map时内存被回收;我会指出,当程序停止时,大多数操作系统也会收集进程的内存。从这个意义上说,泄漏总是短暂的。 (2) 我喜欢你对理论(无限记忆)和实践(有限记忆)的描述。
相关:Is it possible to cause a memory leak in Rust?
请注意,内存泄漏可能被声明为未定义的行为(例如线性类型)。也就是说,开发 Rust 的人可以定义语言中的 UB 是什么。因此,请确保您不要同时说 “内存泄漏不会导致未定义行为,因为它们是安全的。” 因为那将是一个循环定义。以上是关于为啥 Rust 认为泄漏内存是安全的?的主要内容,如果未能解决你的问题,请参考以下文章
不安全的 Rust 中的堆栈引用,但确保不安全不会从堆栈中泄漏?