当使用 massif 使用 valgrind 测量时,Rust 程序的堆大小非常大

Heap size for Rust programs very large when measured with valgrind using massif

我正在尝试测量我正在编写的 Rust 程序的内存大小。我注意到当我使用以下命令测量堆大小时:

valgrind --tool=massif --pages-as-heap=yes ./program

并使用 ms_print 进行测量,内存大小相当大(最初约为 16MB)。最终,我将我的 rust 程序缩减为一个空的主函数:

fn main() {
}

然后我编译了,仍然 我的内存大小是 16MB。我注意到当我使用不同的机器时,完全相同的二进制文件的总大小为 4MB。我的一个朋友在他的机器上用相同的程序尝试了这个,使用相同的 rust/valgrind 版本并且也得到了 4MB 的大小。

我想这是对可能在堆中使用的内存的某种预分配,但我想不出任何方法来控制它。我什至尝试按照 this 指南更改我的分配器,但没有任何改变。

系统详情:

OS version       = Ubuntu 18.04
valgrind version = valgrind-3.13.0
cargo version    = cargo 1.39.0-nightly (3f700ec43 2019-08-19)
rustc version    = rustc 1.39.0-nightly (e44fdf979 2019-08-21)
ms_print         = ms_print-3.13.0
libc version     = ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27

导致您出错的地方是 pages-as-heap,这是由于对大多数现代操作系统(尤其是 linux 上的页面管理方式的误解)。这 并非对所有平台都适用 并且取决于分配器、底层平台和 MMU。实际上,如果你的平台支持虚拟内存,你很可能会有这样的东西。

页面并不总是内存中的强制保留区域。大多数内存函数(mmapmalloc 和其他一些)将分配内存,但这只会被操作 system/kernel 视为指示性的。您可以通过以下测试说服自己:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  void *ptr = malloc(1024 * 1024 * 1024);
  sleep(100);
  return 0;
}

运行 几次,然后...

:~# free -m
              total        used        free      shared  buff/cache   available
Mem:          15930        1716        5553         170        8661       13752
Swap:             0           0           0
:~# ./hog &
[1] 27577
...
[99] 27674
:~# free -m
              total        used        free      shared  buff/cache   available
Mem:          15930        1717        5552         170        8661       13751
Swap:             0           0           0

您可以在 rust 中复制此测试,但您需要比通常在抽象中进行的稍微深入一点才能实现此目的:

fn main() {
  let mut vec:Vec<u8> = vec![];
  vec.reserve(1024 * 1024 * 1024);
}

内存仅在初始化访问后才重要。那时,OS 知道你真的想要它,并将它一直分配给硬件。 Rust 也不例外——除非你使用了一些堆,否则堆只是内核中指向虚拟内存的 mmap

因此,通过使用 pages-as-heap 参数,您只需要在任何重新分配完成之前查找 "potential" 内存,而不是 actual 内存用过的。删除此参数,您将看到您的程序消耗了 300 字节左右的堆(您可以使用 valgrind 本身轻松分析)。

您朋友看到不同输出的原因是他们的页面大小为 4kB 而您的页面大小为 16kB。稍后我会在 rustc 源代码中找到确切的位置——rust 分配了 1024 页。