数据泄露
围绕将引用传递给生成的线程的主要担忧是“使用后释放”错误:即使用指向已经被释放或取消分配的内存区域的指针来访问数据。 如果你正在使用堆上分配的数据,可以通过告诉Rust你将永远不会回收那部分内存来避免这个问题——你选择故意泄露内存。
这可以通过使用Rust标准库中的Box::leak
方法来实现,例如:
#![allow(unused)] fn main() { // 通过包装在一个`Box`中,在堆上分配一个`u32`。 let x = Box::new(41u32); // 告诉Rust你将永远不会释放那个堆分配, // 使用`Box::leak`。这样你就可以得到一个`'static`引用。 let static_ref: &'static mut u32 = Box::leak(x); }
数据泄露的影响范围是进程级的
泄露数据是危险的:如果你持续泄露内存,最终会耗尽内存并因内存不足而崩溃。
#![allow(unused)] fn main() { // 如果让这段代码运行一段时间, // 它最终会消耗掉所有可用内存。 fn 导致内存溢出() { loop { let v: Vec<usize> = Vec::with_capacity(1024); Box::leak(v); } } }
同时,通过Box::leak
泄露的内存并不是真正被遗忘的。操作系统可以将每个内存区域映射到负责它的进程。当进程退出时,操作系统会回收那些内存。
考虑到这一点,如果满足以下条件,泄露内存是可以接受的:
- 你需要泄露的内存量不是无限的或预先已知的,或者
- 你的进程是短暂的,并且你确信在它退出之前不会耗尽所有可用内存
如果应用场景允许,“让操作系统处理它”是一种完全合理的内存管理策略。