【问题标题】:Heap size for Rust programs very large when measured with valgrind using massif使用 massif 使用 valgrind 测量时,Rust 程序的堆大小非常大
【发布时间】:2020-01-20 01:38:13
【问题描述】:

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

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

并使用 ms_print 进行测量,内存大小非常大(最初约为 16MB)。最终,我将我的 rust 程序简化为一个空的 main 函数:

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

【问题讨论】:

  • 那可能是stdout、stdin和stderr的输出输入。这也可能需要分配 rust 以从命令行解析 argv。也许还有其他的事情。为什么要打扰这种事情?这只是在启动时,并且足够快。
  • @Stargateur 这似乎不是由于 stdin、stdout、stderr 和 argv 造成的,因为同一个程序在不同的计算机上给出不同的输出。我认为这也不太可能消耗 16MB 的内存。至于为什么要麻烦,目标是编写一个消耗很少内存但仍然具有良好性能的程序,即如果目标机器的内存量很小(例如旧手机或Arduino),内存是宝贵的资源不能浪费!因此检查内存使用情况的重要性。我相信下面的回答提供了一个很好的答案!
  • 我坚持我的主张,因为 Sébastien 说有 16mo 的页面并不意味着程序真的使用 16mo。请考虑使用no_std 测试您的程序
  • 您需要检查有效内存使用情况。在没有虚拟页面支持或完全没有 MMU 的裸机上运行的程序之外,检查分配了多少并不是一个好的资源(在这种情况下,它们将是平等的)。

标签: rust valgrind massif


【解决方案1】:

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

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

#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);
}

内存只有在初始化访问后才重要。那时,操作系统知道你真的想要它,并将它一直分配给硬件。 Rust 也不例外 - 在你使用该堆的一部分之前,该堆只是内核中指向虚拟内存的 mmap

因此,通过使用pages-as-heap 参数,您只是在寻找任何重新分配完成之前的“潜在”内存,而不是使用的实际内存。去掉这个参数,你会看到你的程序消耗了大约 300 字节的堆(你可以很容易地用 valgrind 本身来分析)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-27
    • 2011-12-25
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 2010-09-17
    相关资源
    最近更新 更多