为什么 `ru_maxrss` 返回的使用量比预期多

为什么 `ru_maxrss` 返回的使用量比预期多

我正在测试一个程序运行器。当我使用 GNU time 1.9 测试下面的代码时

// nul.c
#include <stdio.h>
#include <sys/resource.h>

int main()
{
  struct rusage r_usage;
  getrusage(RUSAGE_SELF, &r_usage);
  printf("%ld\n", sizeof r_usage);
  printf("%ld\n", r_usage.ru_maxrss);
  return 0;
}

编译用

gcc nul.c -o nul

并运行

/usr/bin/time -v ./nul

,它报告

144
576
    Command being timed: "./nul"
    User time (seconds): 0.00
    System time (seconds): 0.00
    Percent of CPU this job got: 0%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 1424
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 61
    Voluntary context switches: 1
    Involuntary context switches: 4
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

最大驻留集大小不满足程序的输出。经过更多测试,maxrssGNU time 报告的大小始终约为 1400kB。并测试下面的代码

// nul2.c
int main(){ return 0; }

编译用

gcc nul2.c -o nul2

并运行

/usr/bin/time -v ./nul2

GNU time 报告 ~1000kBmaxrss使用情况。但是,我的程序中没有使用任何内存空间。那么为什么maxrss使用量不是~0kB,又如何测量程序中实际使用的内存呢?


更新:

我写了一个空汇编程序。

.text
.global _start
_start:
    movl $0, %ebx
    movl $1, %eax
    int  $0x80

编译为

as -o nul.o nul.s
ld -s -o nul nul.o

并用 GNU 时间进行了测试。

    Command being timed: "./nul"
    User time (seconds): 0.00
    System time (seconds): 0.00
    Percent of CPU this job got: 61%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 128
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 13
    Voluntary context switches: 1
    Involuntary context switches: 0
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

还有 128kB 最大 RSS 使用量。它是怎么来的?

答案1

你的数字和我这里的数字相似。

不要忘记您的程序使用库。 (例如,函数printf是程序的一部分。它的缓冲区在程序启动时或稍后分配,或两者兼而有之。回想一下,如果代码加载到内存中,则代码也计入 RSS。)这解释了非零数量以及该数量在进程完成之前增加的事实。

如果您以某种方式停止进程的执行(通过读取指令或调试器),您可以使用/proc/<pid>/...或 例如通过慢速lsof程序检查其内存。

特别是,您的程序正在使用/usr/lib/x86_64-linux-gnu/libc.so.6(或类似)硬盘上的 2.2MB(并非所有内容都需要加载)。


可能就是这样

/usr/bin/time -v ./nul2 "$(seq -w 1 16000)"

报告的数字稍高一些,因为命令行也成为进程内存的一部分。



更新:

现在你已经移动到了更低的水平。恭喜。您跳过了使用 C 编译器以及使其不包含标准库的选项的可能性。 (随机关联可能是错误的方向。)

我认为您已经知道一些答案Why(这就是您提出问题的方式)(因此这个问题已经得到解答,可能好可能更糟),并且可能您想提出一个新问题,例如“如何使用 less 编译程序”比 xxx 这种/或/那种记忆”。我认为你应该解释一下你的动机。您想以最小的占用空间运行流程吗?为什么?您打算使用最少的硬件吗?或者您即将运行一百万个进程?

对于您的汇编程序,我们可以在gdb(使用break _startr)中运行它并查看

cat  /proc/222226/maps     # the number is PID of the process
00400000-00401000 r--p 00000000 103:04 1049144                           /home/h/tmpdir/asm.tmp.1
00401000-00402000 r-xp 00001000 103:04 1049144                           /home/h/tmpdir/asm.tmp.1
7ffff7ff9000-7ffff7ffd000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0                          [vdso]
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

cat  /proc/222226/maps | tr a-z A-Z | awk 'BEGIN {print "ibase=16";}; {print $1}; ' | bc -l
-4096
-4096
-16384
-8192
-135168
-4096

但我不知道这对 RSS 或其他什么有多大贡献。看了一下,/proc/222226/smaps我没有看到太多 rss 。

顺便说一句:我已经提到过,命令行的内容会占用内存。对于环境来说也是如此。

实际报告什么/usr/bin/time它如何启动程序?如果它通过fork(显式或隐藏在库组合中)启动它,则它自己的内存使用量将影响已用内存。下面的内容看起来很有趣:

$  /usr/bin/time -v nonexisting
/usr/bin/time: cannot run nonexisting: No such file or directory
Command exited with non-zero status 127
    Command being timed: "nonexisting"
...
    Maximum resident set size (kbytes): 768
    Minor (reclaiming a frame) page faults: 40

因此,time使用几乎大量的新内存来从失败exec(或某些情况)中恢复并打印一条消息cannot run...,并在该操作中出现 40 个页面错误。 (可能大部分巨额资金都花在了意想不到的清理工作和退出分叉进程的艰苦工作上,但无论如何。)

摘要:我建议开始一个新问题,而How不是Why.

相关内容