有没有办法在分叉之前将只读变量加载到内存中,并将它们保存在那里,而不会占用virt内存x子内存的数量?
人们普遍认为只读存储器默认情况下是共享的,并且在写入时被复制。我运行了一个测试,发现这是不正确的:
#!/usr/bin/perl
my $data;
$$data = 'a'x 1_000_000; #keep it in a ref just in case that matters
foreach (0..10){
last unless my $pid = fork();
}
<STDIN>;
当进程位于STDIN时,我检查顶部:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15982 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15983 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15984 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15985 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15986 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15987 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15988 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15989 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15990 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15991 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
15992 wdev 20 0 121m 2540 188 S 0.0 0.1 0:00.00 foo.t
可以肯定的是,几乎所有的内存都在各个子进程中。
是我遗漏了什么,还是fork一个perl进程真的复制了每个子进程的整个数据结构集?
2条答案
按热度按时间1sbrub3j1#
这可能与操作系统有关,也可能你看到的不是你认为看到的。我修改了你的测试脚本:
使用
./forktest | grep Mem
运行它,我得到如下输出:其中第二列数字(第三列)是系统RAM的总使用量。请注意,当在程序开始时分配
$data
时,它从2866552增加到2917888,然后在分叉完成后保持相当稳定。我怀疑您在
top
中看到的是,它使用了IPC特定意义上的“共享内存”(即,已显式请求并分配为“共享”的内存块),并且当前可用于多个进程的页面在写时复制的基础上不符合该定义。0qx6xfy62#
perl docs on fork说“文件描述符(有时是这些描述符上的锁)是共享的,而其他所有内容都是复制的。”
实际上这意味着进程的所有(代码和)数据都被复制到fork上,但是进程地址空间中的文件描述符基本上是对共享内核结构的引用。因此父进程和子进程可以访问同一个文件。