Rust 分析堆内存分配

5,302 阅读4分钟

关于为什么要计算内存使用情况?

因为内存是昂贵的,云供应商根据CPU/磁盘/网络和内存来区分服务。计算应用程序占用多少内存是一个非常有用的技能。

Example

这篇博文正是来剖析Rust应用程序的堆使用情况。

例子如下:应用程序正在读取一个可能存在的大csv到内存中,然后存储标题和字段,以便以后通过索引访问。下面我们使用一个实例项目来演示:

cargo new --bin heaptrace_csv

其中我们需要的 struct 如下:

use std::io::{self, BufRead};

// src/main.rs
#[allow(dead_code)]
struct DataRecord {
    fields: Vec<String>,
}

#[allow(dead_code)]
struct DataSheet {
    headers: Vec<String>,
    rows: Vec<DataRecord>,
}

以及计算和存储逻辑:

// src/main.rs
fn split_str(s: String) -> Vec<String> {
    s.split(',').map(str::to_string).collect()
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = std::fs::File::open("./example.csv")?;
    let reader = io::BufReader::new(file);
    let mut lines = reader.lines();

    let sheet = DataSheet {
        headers: split_str(lines.next().ok_or("empty header")??),
        rows: lines
            .map(|l| DataRecord {
                fields: split_str(l.unwrap()),
            })
            .collect(),
    };
    Ok(())
}

该程序从 example.csv 创建 BufReader :

du -h example.csv
976K    example.csv
❯ wc -l example.csv
12427 example.csv

计算内存使用

为了计算一个进程在Linux上的内存使用情况,我们可以使用 pmap,但要做到这一点,我们必须添加一些东西,使我们的程序等待计算。让我们在main方法的最后添加简单的sleep:

// end of main method
std::thread::sleep(std::time::Duration::from_secs(10))

因此,为了简化理解内存地址的过程,我们可能想禁用 地址空间布局随机化。这是操作系统使用的一种技术,在进程的地址空间中引入一些随机性:

# read <https://askubuntu.com/questions/318315/how-can-i-temporarily-disable-aslr-address-space-layout-randomization>
# for more information
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
# to enable it back on after having fun: 
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

然后我们可以用 pmap 分析一下:

❯ cargo run -q --release &

❯ pmap -x $(pgrep heaptrace_csv)

81044:   /home/flakm/programming/flakm/rustberry/target/release/heaptrace_csv
Adres                 KB     RSS  Brudne Tryb  Odwzorowanie
0000555555554000      28      28       0 r---- heaptrace_csv
000055555555b000     228     228       0 r-x-- heaptrace_csv
0000555555594000      56      56       0 r---- heaptrace_csv
00005555555a2000      16      16      16 r---- heaptrace_csv
00005555555a6000       4       4       4 rw--- heaptrace_csv
00005555555a7000    5080    5052    5052 rw---   [ anon ]
00007ffff7d19000     388     292     292 rw---   [ anon ]
00007ffff7dab000       4       0       0 -----   [ anon ]
00007ffff7dac000      16       8       8 rw---   [ anon ]
00007ffff7db0000     152     148       0 r---- libc-2.33.so
00007ffff7dd6000    1352     796       0 r-x-- libc-2.33.so
00007ffff7f28000     312     156       0 r---- libc-2.33.so
00007ffff7f76000      12      12      12 r---- libc-2.33.so
00007ffff7f79000      12      12      12 rw--- libc-2.33.so
00007ffff7f7c000      36      12      12 rw---   [ anon ]
00007ffff7f85000       4       4       0 r---- libdl-2.33.so
00007ffff7f86000       4       4       0 r-x-- libdl-2.33.so
00007ffff7f87000       4       0       0 r---- libdl-2.33.so
00007ffff7f88000       4       4       4 r---- libdl-2.33.so
00007ffff7f89000       4       4       4 rw--- libdl-2.33.so
00007ffff7f8a000      28      28       0 r---- libpthread-2.33.so
00007ffff7f91000      56      56       0 r-x-- libpthread-2.33.so
00007ffff7f9f000      20       0       0 r---- libpthread-2.33.so
00007ffff7fa4000       4       4       4 r---- libpthread-2.33.so
00007ffff7fa5000       4       4       4 rw--- libpthread-2.33.so
00007ffff7fa6000      16       4       4 rw---   [ anon ]
00007ffff7faa000      12      12       0 r---- libgcc_s.so.1
00007ffff7fad000      68      64       0 r-x-- libgcc_s.so.1
00007ffff7fbe000      12      12       0 r---- libgcc_s.so.1
00007ffff7fc1000       4       0       0 ----- libgcc_s.so.1
00007ffff7fc2000       4       4       4 r---- libgcc_s.so.1
00007ffff7fc3000       4       4       4 rw--- libgcc_s.so.1
00007ffff7fc4000       8       8       8 rw---   [ anon ]
00007ffff7fc6000      16       0       0 r----   [ anon ]
00007ffff7fca000       8       4       0 r-x--   [ anon ]
00007ffff7fcc000       4       4       0 r---- ld-2.33.so
00007ffff7fcd000     144     144       0 r-x-- ld-2.33.so
00007ffff7ff1000      40      40       0 r---- ld-2.33.so
00007ffff7ffb000       8       8       8 r---- ld-2.33.so
00007ffff7ffd000       8       8       8 rw--- ld-2.33.so
00007ffffffd1000     184      64      64 rw---   [ stos ]
ffffffffff600000       4       0       0 --x--   [ anon ]
---------------- ------- ------- ------- 
razem kB            8372    7308    5524

TODO!!!

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情