我希望能够测试一些关于各种命令行实用程序的内存复杂性的猜测。
举一个简单的例子
grep pattern file
我想了解内存使用情况如何随pattern
的大小和file
的大小而变化。
对于时间复杂度,我会猜测,然后运行
time grep pattern file
在各种大小的输入上看看我的猜测是否在现实中得到证实,但我不知道如何为记忆做这件事。
一种可能性是启动作业并定期对内存使用进行采样的包装脚本,但这似乎不够优雅,不太可能提供真正的高水印。
我看过time -v
建议,但我的机器上没有可用的标志(在OSX上运行bash)并且不知道在哪里可以找到支持它的版本。
我还看到在Linux上,这些信息可以通过proc
文件系统获得,但同样,在我的上下文中我无法使用它。
我想知道dtrace
是否可能是一个合适的工具,但我又担心一个简单的基于样本的数字可能不是真正的高水印?
有没有人知道适合OSX的工具或方法?
修改
我删除了两个提及磁盘使用的内容,这些内容只是旁白,可能会分散问题的主要内容。
答案 0 :(得分:3)
您的问题很有趣,因为如果没有应用程序源代码,您需要对内存使用的构成做一些假设。即使您使用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#
this article by Brendan Gregg中包含有关内存分配器的更全面的讨论。它为你的问题提供了比我自己更好的答案。特别是,它包含一个名为memleak.d
的脚本的链接;修改此项以包括分配的时间戳&解除分配,以便您可以按时间对其输出进行排序。然后,也许使用附带的脚本作为示例,使用perl
来跟踪当前未完成的总分配和高水位线。这样的DTrace / perl组合将适用于跟踪多线程进程。
答案 1 :(得分:1)
您可以使用/usr/bin/time -l
(不是macOS中内置的time
的{em>不是),并读取“最大居民集大小”,这并不是精确的高水位线,而是可能会给您一些想法。
$ /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
此字段的含义在here中进行了说明。
答案 2 :(得分:0)
尝试了getrusage()
。结果不正确。尝试过的乐器。痛苦不已。
迄今为止最好的解决方案: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`