在某些情况下,我们会出于某种原因故意泄漏内存。在这些情况下,我们会显式调用Box::leak()
或mem::foget()
之类的函数。此外,有时程序的目的可能是向集合中添加项而不删除项。然而,由其它原因引起的内存泄漏,如强引用对弱引用的误用,几乎不会发生(我认为不可能)。为什么编译器不跟踪每个具有引用计数的智能指针,并且在整个程序退出时,如果任何指针的计数不为0,则拒绝编译?也就是说,一个程序只有在主函数的drop阶段之后所有的Arc和Rc的引用计数都为0时才能编译。如果上面的方法不能实现,我希望知道为什么不能。
1条答案
按热度按时间nkoocmlb1#
为了知道程序是否会终止,我们需要求解halting problem,不幸的是,阿兰·图灵证明了不存在一般的解,这本身就排除了任何此类分析。
更一般地说,编译器不知道运行时会发生什么,它可能依赖于各种输入,如命令行参数、环境变量、文件系统的状态(存在什么目录/文件以及它们包含什么)、诸如从远程API或数据库获取信息之类的网络操作的结果等等。总的来说,我们可以将程序外部的所有这些信息称为其“环境”。程序的环境可以影响程序将做什么,并且内存泄漏可能在某些环境中发生,但在其它环境中不会发生。
此外,在Rust中,当
main()
返回时,所有正在运行的线程将自动终止,并且这种终止是强制的;线程所拥有的任何值都不会运行析构函数,因此它们所拥有的任何Arc
都没有机会被正确地清除。这意味着任何使用线程的程序都很容易导致泄漏检查生成假阳性。这种静态分析根本不可行。
事实上,我们拥有引用计数类型的原因之一是为了处理编译器无法证明程序安全性的情况。这些类型从根本上向编译器隐藏了所包含值的“真实”生存期。要求编译器计算出存储在一个向编译器隐藏了生存期的类型中的值的生存期是一个矛盾。