如果我的文本文件(textfile
)包含文本行和
perlscript
)
#!/usr/bin/perl
use strict;
use warnings;
my $var;
$var.=$_ while (<>) ;
print $var;
命令在终端
中运行cat ./textfile | ./perlscript | ./perlscript | ./perlscript
如果我在1kb文本文件上运行上述代码,而不是程序堆栈等,我是否使用过4Kb内存?或者当我从STDIN
拉出来时,我是否释放了那个记忆,因此,我只会使用1 Kb?
用另一种方式说出上述问题,是从STDIN
复制到内存使用中有效中立的变量吗?或者加倍记忆消耗?
答案 0 :(得分:2)
更像2kB,但1kB文件不是一个很好的例子,因为你的读缓冲区可能比那个更大。让我们改为1GB的文件。然后你的峰值内存使用量可能会大约2GB加上一些开销。 cat
使用可忽略不计的内存,只是将其输入改组为输出。第一个perl进程必须读取所有输入并将其存储在$var
中,使用1GB(加一点点)。然后它开始将它写入第二个,它将它存储到自己的私有$var
,也使用1GB(加一点点),所以我们高达2GB。当第一个perl进程完成写入时,它退出,关闭其stdout,导致第二个perl进程在stdin上获得EOF,这是使while(<>)
循环终止和第二个perl进程开始写入的原因。此时第三个perl进程开始读取并存储到自己的$var
,使用另一个1GB,但第一个已经消失,所以我们仍然在2GB附近。然后第二个perl进程结束,第三个进程开始写入stdout,然后退出。
答案 1 :(得分:2)
你已经得到了一个很好的答案,但我对我的猜测并不满意,所以我决定测试我的假设。
我创建了一个名为streamstream
的简单C ++程序,只需要STDIN并以1024字节的块将其写入STDOUT。它看起来像这样:
#include <stdio.h>
int main()
{
const int BUF_SIZE = 1024;
unsigned char* buf = new unsigned char[BUF_SIZE];
size_t read = fread(buf, 1, BUF_SIZE, stdin);
while(read > 0)
{
fwrite(buf, 1, read, stdout);
read = fread(buf, 1, BUF_SIZE, stdin);
}
delete buf;
}
为了测试程序如何使用内存,我使用valgrind
运行它,同时将输出从一个输出到另一个,如下所示:
cat onetwoeightk | valgrind --tool=massif ./streamstream | valgrind --tool=massif ./streamstream | valgrind --tool=massif ./streamstream | hexdump
...其中onetwoeightk
只是一个128KB的随机字节文件。然后我在massif输出上使用ms_print
工具来帮助解释。显然,程序本身及其堆的开销很大,但它从大约80KB开始,并且从未超过这个,因为它一次只能将STDIN啜饮一千字节。
数据一次从进程传递到进程1千字节。我们的整体内存使用量将达到1千字节*处理流的程序实例数。
现在让我们执行你的perl程序正在做的事情 - 我将读取整个流(每次都增加我的缓冲区),然后将它全部写入STDOUT。然后我再次检查valgrind输出。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
const int BUF_INCREMENT = 1024;
unsigned char* inbuf = (unsigned char*)malloc(BUF_INCREMENT);
unsigned char* buf = NULL;
unsigned int bufsize = 0;
size_t read = fread(inbuf, 1, BUF_INCREMENT, stdin);
while(read > 0)
{
bufsize += read;
buf = (unsigned char *)realloc(buf, bufsize);
memcpy(buf + bufsize - read, inbuf, read);
read = fread(inbuf, 1, BUF_INCREMENT, stdin);
}
fwrite(buf, 1, bufsize, stdout);
free(inbuf);
free(buf);
}
不出所料,在程序执行过程中,内存使用率攀升至超过128千字节。
KB
137.0^ :#
| ::#
| ::::#
| :@:::#
| :::@:::#
| :::::@:::#
| :@:::::@:::#
| :@:@:::::@:::#
| ::@:@:::::@:::#
| :@::@:@:::::@:::#
| :@:@::@:@:::::@:::#
| @::@:@::@:@:::::@:::#
| ::@::@:@::@:@:::::@:::#
| :@::@::@:@::@:@:::::@:::#
| @:@::@::@:@::@:@:::::@:::#
| ::@:@::@::@:@::@:@:::::@:::#
| :@::@:@::@::@:@::@:@:::::@:::#
| @::@::@:@::@::@:@::@:@:::::@:::#
| ::@::@::@:@::@::@:@::@:@:::::@:::#
| ::::@::@::@:@::@::@:@::@:@:::::@:::#
0 +----------------------------------------------------------------------->ki
0 210.9
但问题是,由于这种方法,总内存使用量是多少?我无法找到一个很好的工具来测量一组交互过程随时间的内存占用情况。 ps
在这里看起来不够准确,即使我插入了一堆睡眠。但我们可以解决这个问题:128KB缓冲区只在程序执行结束后才会被写入。但是在编写流时,程序的另一个实例会构建自己的128KB缓冲区。所以我们知道我们的内存使用量将攀升到2x 128KB。但是,通过链接更多的程序实例,赢得上升到3x或4x 128KB,因为我们的实例释放内存并在写入STDOUT后立即关闭。