以下代码创建框,每个框都指向 4096 字节的块。如果我在发布时运行它,一切都会被优化掉:(,但在调试时,这会按预期运行并泄漏大量内存......或者是吗?
fn main() {
for _ in 0..1000 {
for _ in 0..100000 {
let b = Box::new([!0u64; 1 << 10]);
std::mem::forget(b);
}
let mut buf = String::new();
let _ = std::io::stdin().read_line(&mut buf);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么这不被认为是不安全的?
Joe*_*lay 11
其他答案提供了关于为什么今天这被认为是安全的很好的信息,但了解这种情况的背景也很有用。
很久以前(1.0 之前),Rust确实保证安全代码永远不会导致内存泄漏(因此mem::forget被标记为unsafe fn)。因此,其他不安全的代码也依赖于这个假设。
然而,事实证明这是完全不正确的——例如,您可以通过创建循环来轻松创建内存泄漏Rc!结果,其中的几个 API std(最值得注意的是作用域线程的原始实现)必须被删除或重写,因为它们不健全。
这在 Rust 社区中偶尔被称为“ leakpocalypse ”,它导致 Rust 的内存安全定义被更改为不再涵盖内存泄漏。由于泄漏内存不再被认为是不安全的,mem::forget因此已更改为不再是unsafe fn.
\n\n忘记没有被标记为不安全,因为Rust\xe2\x80\x99s的安全保证不包括析构函数将始终运行的保证。例如,程序可以使用 Rc 创建引用循环,或者调用 process::exit 退出而不运行析构函数。因此,允许安全代码中的 mem::forget 并不会从根本上改变 Rust\xe2\x80\x99s 的安全保证。
\n
Rust 中的“安全”意味着一些非常具体的事情。Rust 中的“安全”仅意味着不可能访问无效内存,或者对一个对象有多个可变引用。这本书描述得非常好:
\n\n\nRust 对于其他可疑操作是相当宽容的。\nRust 认为它“安全”:
\n\n
\n- 僵局
\n- 有竞争条件
\n- 内存泄漏
\n- 无法调用析构函数
\n- 溢出整数
\n- 中止程序
\n- 删除生产数据库
\n
std::mem::forget允许您泄漏内存,这是明确允许的。如果您想取回内存(例如使用 transmute 或 with Box::from_raw_parts),您将需要不安全的代码,因为这可能违反可变引用规则。
| 归档时间: |
|
| 查看次数: |
577 次 |
| 最近记录: |