68、内存泄漏

泄露数据

向生成的线程传递引用的主要问题是use-after-freebug:使用已经freedde-allocated的指针访问数据。

如果我们使用的是堆分配的内存,我们可以通过告诉Rust永远不会回收该内存来避免这个问题:我们故意选择内存泄漏

例如,可以使用 Rust 标准库中的 Box::leak 方法来做到这一点:

// 在堆上分配一个 `u32` ,将其封装在一个 `Box` 中。
let x = Box::new(41u32);
// 告诉 Rust,你永远不会释放该堆分配
// 使用 `Box::leak`。这样,我们就可以得到一个 "静态引用"。
let static_ref: &'static mut u32 = Box::leak(x);

 

数据泄露仅限于当前范围内

泄漏数据是很危险的:如果不断泄漏内存,最终会耗尽内存,并因内存不足错误而崩溃。

// 如果让它运行一段时间、
// 最终会耗尽所有可用内存。
fn oom_trigger() {
    loop {
        let v: Vec<usize> = Vec::with_capacity(1024);
        v.leak();
    }
}

同时,通过leak方法泄露的内存并不会被真正遗忘。

操作系统可以将每个内存区域映射到负责该区域的进程。当进程退出时,操作系统将收回该内存。

 

考虑到这一点,在以下情况下泄露内存是没有问题的:

  • 需要泄漏的内存量是有边界的/预先知道的
  • 你的进程持续时间很短,而且你确信不会在进程退出前耗尽所有可用内存

 

如果你的用例允许,"让操作系统来处理 "是一种完全有效的内存管理策略。

 

练习

// TODO: Given a vector of integers, leak its heap allocation.
//  Then split the resulting static slice into two halves and
//  sum each half in a separate thread.
//  Hint: check out `Vec::leak`.
// TODO: 给定一个整数向量,泄漏其堆分配。
// 然后将生成的静态切片分成两半,并在单独的线程中对每一半进行求和。
// 在一个单独的线程中对每一半求和。
// 提示:查看 `Vec::leak`。

use std::thread;

pub fn sum(v: Vec<i32>) -> i32 {
    let v = v.leak();//类似于创建一个静态引用
    let mid = v.len() / 2;
    let (v1, v2) = v.split_at(mid);//分出两个切片多线程计算和

    let handle1 = thread::spawn(move || v1.into_iter().sum::<i32>());
    let handle2 = thread::spawn(move || v2.into_iter().sum::<i32>());

    handle1.join().unwrap() + handle2.join().unwrap()
}

 

好久没有在博客更新过Rust学习日记了,这很糟糕。最近这段时间也是挺忙的,去忙软考和学校迎新晚会的弹幕抽奖系统开发了,后面还会有期末考试和英语四级考试,唉,事情真多,要是大学没有这么多事情就好了。

阅读剩余
THE END