【问题标题】:peak memory measurement of long running process in linuxlinux中长时间运行进程的峰值内存测量
【发布时间】:2009-07-03 18:49:49
【问题描述】:

如何监控 Linux 中进程消耗的峰值内存? 这不是我可以在内部修改以测量峰值内存使用的程序。

我真的不想要详细的测量,也不希望它们过度减慢我的程序。所以 valgrind 或任何重量级的东西不是我要找的... 和之前的其他帖子一样 [Peak memory usage of a linux/unix process, time -v 似乎没有报告我机器的内存...

我可以运行 top 或 ps 并提取内存消耗的字符串 我的进程 id 使用一个简单的脚本。但是,我的进程运行了大约 20-30 分钟,所以我希望能够记录并获得最大值。 我可以容忍粗粒度的样本……每 1 分钟左右……具体来说我该怎么做-> 1. 在 zsh 中 fork 这个简单的 mem-measure 脚本? 2. 待测进程结束时杀死它?

【问题讨论】:

    标签: linux memory


    【解决方案1】:

    只需使用 top -n 迭代指定次数,使用 -d 来延迟更新之间的时间。您也可以通过 grepping pid 仅获取与您的进程相关的输出,例如:

    top -n 30 -d 60 | grep <process-id>
    

    阅读顶部手册页了解更多信息

    man top
    

    当然,你也可以使用awk来抓取你需要的列。

    【讨论】:

      【解决方案2】:

      其实我之前说过的:

      """

      试试

      /usr/bin/time -v yourcommand
      

      这应该会有所帮助。如果你只使用“时间”,bash 将执行内置(没有“-v”)

      """

      不起作用(返回 0)。

      我制作了以下 perl 脚本(我称之为 smaps):

      #!/usr/bin/perl
      use 5.010;
      use strict;
      use warnings;
      my $max = 0;
      while( open my $f, '<', "/proc/$ARGV[0]/smaps" ) {
        local $/; $_ = <$f>;
        $max = $1 if /Rss:\s*(\d+)/ and $1 > $max;
        open my $g, '>', '/tmp/max';
        say $g $max
      }
      

      然后我调用它(例如,查看 qgit 的内存使用情况):

      bash -c './smaps $$ & exec qgit'
      

      使用单引号,以便“女儿”shell 解释 $$(这将与 exec 之后的 qgit 的 PID 相同)。 这个答案,我测试过:-D

      HTH

      【讨论】:

      • 输出 2 件...仍然没用 :( 用户时间(秒):16.50 系统时间(秒):0.47 此作业获得的 CPU 百分比:100% 已用(挂钟)时间( h:mm:ss 或 m:ss): 0:16.96 平均共享文本大小 (kbytes): 0
      • 平均非共享数据大小(kbytes):0 平均堆栈大小(kbytes):0 平均总大小(kbytes):0 最大驻留集大小(kbytes):0 平均驻留集大小(kbytes): 0 主要(需要 I/O)页面错误:0 次要(回收帧)页面错误:255315 自愿上下文切换:1211 非自愿上下文切换:1232 交换:0 文件系统输入:0 文件系统输出:68472 发送的套接字消息:0收到的套接字消息:0 页面大小(字节):4096
      【解决方案3】:

      Valgrindmassif 不应该太重,但是,我建议使用 /proc。您可以轻松编写自己的监控脚本。这是我的,为了您的方便:

      #!/bin/bash
      
      ppid=$$
      maxmem=0
      
      $@ &
      pid=`pgrep -P ${ppid} -n -f $1` # $! may work here but not later
      while [[ ${pid} -ne "" ]]; do
          #mem=`ps v | grep "^[ ]*${pid}" | awk '{print $8}'`
              #the previous does not work with MPI
              mem=`cat /proc/${pid}/status | grep VmRSS | awk '{print $2}'`
          if [[ ${mem} -gt ${maxmem} ]]; then
              maxmem=${mem}
          fi
          sleep 1
          savedpid=${pid}
          pid=`pgrep -P ${ppid} -n -f $1`
      done
      wait ${savedpid} # don't wait, job is finished
      exitstatus=$?   # catch the exit status of wait, the same of $@
      echo -e "Memory usage for $@ is: ${maxmem} KB. Exit status: ${exitstatus}\n"
      

      【讨论】:

        【解决方案4】:

        您可以使用 munin-node 插件来执行此操作,但它有点重量级。 http://munin.projects.linpro.no/

        【讨论】:

          【解决方案5】:

          /proc/pid/smaps 与 /proc/pid/maps 一样,只提供有关虚拟内存映射的信息,而不是实际的物理内存使用情况。 top 和 ps 给出 RSS,这(取决于您想知道的内容)可能不是内存使用情况的良好指标。

          如果您在 2.6.28.7 之后的 Linux 内核上运行,一个不错的选择是使用 Pagemap 功能。在www.eqware.net/Articles/CapturingProcessMemoryUsageUnderLinux 对此进行了讨论,并提供了一些工具的来源。

          页面收集工具旨在捕获所有进程的内存使用情况,因此可能会带来比您想要的更大的 CPU 负担。但是,您应该能够轻松地对其进行修改,以便它仅捕获特定进程 ID 的数据。这将减少足够的开销,以便您可以轻松地每隔几秒钟运行一次。我没有尝试过,但我认为页面分析工具应该无需更改即可运行。

          均衡器

          【讨论】:

            【解决方案6】:

            这取决于您要监控的内存类型。

            通过对所有进程(不是所有线程)的数量进行排序来监控以下 M.a.p.d 将让您监控每个进程使用的 malloc 物理内存。

            您可以编写一个 c 程序以使其更快,但我认为 awk 是为此目的的最低选择。

            • M.a 匿名映射内存
              • .p 私有
                • .d 脏 == malloc/mmapped 堆和堆栈分配和写入内存
                • .c clean == malloc/mmapped 堆和堆栈内存一旦分配、写入、然后释放,但尚未回收
              • .s 共享
                • .d 脏 == 应该没有
                • .c clean == 应该没有
            • M.n 命名映射内存
              • .p 私有
                • .d 脏 == 文件映射写入内存私有
                • .c clean == 映射程序/库文本私有映射
              • .s 共享
                • .d 脏 == 文件映射写入内存共享
                • .c clean == 映射库文本共享映射

            我更愿意按以下方式获取数字,以便以最少的开销获得实数。
            您必须将这些总结起来才能将 ps 显示为 RSS 的内容进行划分,并获得更准确的数字以免混淆。

            M.a.p.d:

             awk '/^[0-9a-f]/{if ($6=="") {anon=1}else{anon=0}} /Private_Dirty/{if(anon) {asum+=$2}else{nasum+=$2}} END{printf "sum=%d\n",asum}' /proc/<pid>/smaps
            

            M.a.p.c:

             awk '/^[0-9a-f]/{if ($6=="") {anon=1}else{anon=0}} /Private_Clean/{if(anon) {asum+=$2}else{nasum+=$2}} END{printf "sum=%d\n",asum}' /proc/<pid>/smaps
            

            M.n.p.d:...等等

            【讨论】:

              【解决方案7】:

              与其每秒轮询 /proc 十亿次,不如直接处理 strace 的输出?

              http://tstarling.com/blog/2010/06/measuring-memory-usage-with-strace/

              【讨论】:

              • 这不考虑内存映射文件,它确实不像常驻内存那样消耗内存。
              【解决方案8】:

              pagemap 内核接口可以提供准确的内存指标 - 在 libpagemap 库https://fedorahosted.org/libpagemap/ 中使用。库还提供了用户空间实用程序,因此您可以立即开始监控内存。

              【讨论】:

                【解决方案9】:

                测量峰值/高水位 RSS 内存使用情况的更好替代方法cgmemtime 工具,可在此处获得:

                https://github.com/gsauthof/cgmemtime

                它与 /usr/bin/time 一样易于使用,并且不会因 Valgrind 的地块而减速。 此外,它基于一个名为 cgroupskernel 功能,因此比其他轮询方法更准确。

                【讨论】:

                  【解决方案10】:

                  如果你只需要监控单个进程,你可以这样做:

                  #!/bin/bash
                  PID=$(pidof myprog)
                  while true; do
                      printf "%s: %s KB\n" "$(date --iso=sec)" "$(grep VmHWM: /proc/$PID/status | awk '{print $2}')";
                      sleep 5s;
                  done
                  

                  请注意,除了目前的峰值使用量之外,您还可以轻松修改它以打印当前内存使用量 (VmRSS)。

                  另请注意,VmHWM 是最大常驻内存 (RAM) 使用量,如果您对虚拟内存使用量感兴趣,请使用 VmPeak

                  如果您的进程分叉并且您想测量一组进程的总 RAM 使用情况,则必须使用内存 cgroup,因为这是实际查看短期峰值使用情况的唯一方法。任何尝试轮询当前内存使用情况的解决方案都会错过比轮询速率短的峰值。

                  【讨论】:

                    猜你喜欢
                    • 2010-10-20
                    • 2019-02-21
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-12-02
                    • 1970-01-01
                    • 2017-09-20
                    • 1970-01-01
                    相关资源
                    最近更新 更多