如何在OSX上获取内存使用高水位标记

6

我希望能够测试各种命令行实用程序的内存复杂度,并且需要一个简单的例子。

以一个简单的例子来说明:

grep pattern file

我希望看到有关patternfile大小变化时内存使用情况的变化。就时间复杂性而言,我会先猜测,然后运行。
time grep pattern file

在不同大小的输入上检查我的猜测是否符合现实,但我不知道如何针对内存做到这一点。
一种可能的方法是编写一个包装脚本来启动作业并定期采样内存使用情况,但这似乎不太优雅,并且不太可能给出真正的高水位线。
我看过建议使用 "time -v",但我在我的机器上(在OSX上运行bash)没有该标志可用,也不知道在哪里找到支持它的版本。
我还看到,在Linux上,通过proc文件系统可以获取此信息,但在我的情况下无法使用。
我想知道dtrace是否可能是一个适当的工具,但我担心简单的基于样本的数字可能不是真正的高水位线?
有人知道在OSX上适用的工具或方法吗?
编辑
我删除了两个提到 "磁盘使用" 的提及,它们只是旁白,可能会分散问题的主要内容。
3个回答

6

你的问题很有趣,因为在没有应用程序源代码的情况下,你需要做出一些关于内存使用的假设。即使你使用 procfs,结果也会误导:常驻集大小和总虚拟地址空间都会被高估,因为它们将包括诸如程序文本之类的多余数据。

特别是对于小型命令,跟踪单个分配会更容易,但即使在那里,你也需要确保包括所有可能的来源。除了 malloc() 等之外,进程还可以使用 brk() 扩展其堆或使用 mmap() 获取匿名内存。

以下是一个跟踪 malloc() 的 DTrace 脚本;你可以扩展它以包括其他分配函数。请注意,它不适用于多线程程序,因为它使用了一些非原子变量。

bash-3.2# cat hwm.d
/* find the maximum outstanding allocation provided by malloc() */
size_t total, high;

pid$target::malloc:entry
{
    self->size = arg0;
}

pid$target::malloc:return
/arg1/
{
    total += self->size;
    allocation[arg1] = self->size;
    high = (total > high) ? total : high;
}

pid$target::free:entry
/allocation[arg0]/
{
    total -= allocation[arg0];
    allocation[arg0] = 0;
}

END
{
    printf("High water mark was %d bytes.\n", high);
}
bash-3.2# dtrace -x evaltime=exec -qs hwm.d -c 'grep maximum hwm.d'
/* find the maximum outstanding allocation provided by malloc() */
High water mark was 62485 bytes.

bash-3.2#

关于内存分配器的更全面讨论,可以参考Brendan Gregg写的这篇文章。相比我自己的回答,它提供了更好的答案。特别是,它包含一个名为memleak.d的脚本链接;修改它以包括分配和释放的时间戳,以便可以按时间排序其输出。然后,也许可以使用附带的脚本作为示例,使用perl跟踪当前未完成的总分配和最高水位线。这样的DTrace/perl组合适用于跟踪多线程进程。


4
你可以使用/usr/bin/time -l命令(这不是macOS内置的time命令),并查看“最大常驻集大小”,这不完全是高峰值,但可以给你一些想法。
$ /usr/bin/time -l ls
...
        0.00 real         0.00 user         0.00 sys
    925696  maximum resident set size
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
       239  page reclaims
         0  page faults
         0  swaps
         0  block input operations
         0  block output operations
         0  messages sent
         0  messages received
         0  signals received
         3  voluntary context switches
         1  involuntary context switches

这个字段的含义在这里有解释:这里

0

尝试使用getrusage()。结果不准确。尝试了Instruments,真是让人头疼。

目前最好的解决方案:valgrind + massif

  • 基于命令行:易于运行、脚本化和自动化;无需打开应用程序、点击菜单等等;可以在后台运行等等
  • 提供一个可视化图表--在您的终端中--显示随时间变化的内存使用情况
    valgrind --tool=massif /path/to/my_program arg1 ...
    ms_print `ls -r massif.out.* | head -1` | grep Detailed -B50

要查看更多细节,请运行ms_print `ls -r massif.out.* | head -1`


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接