假设我输入cd
了我的shell。cd
那时候是从内存加载的吗?我的直觉是,这些内置命令在内核加载后会预先加载到系统内存中,但是有人坚持说只有在我实际调用命令时(在外壳上按Enter键)才加载它们。您能否告诉我是否有参考文献对此进行解释?
假设我输入cd
了我的shell。cd
那时候是从内存加载的吗?我的直觉是,这些内置命令在内核加载后会预先加载到系统内存中,但是有人坚持说只有在我实际调用命令时(在外壳上按Enter键)才加载它们。您能否告诉我是否有参考文献对此进行解释?
Answers:
假设我在外壳中输入cd。那时从内存中装入了cd吗?我的直觉是,这些内置命令在内核加载后预加载到系统内存中,但是有人坚持只有在我实际调用该命令时才加载它们。
从广义上讲,其他答案是正确的-内置程序随外壳一起加载,独立程序在调用时被加载。但是,一个非常狡猾的狡猾的“某人”可能会坚持认为这不是那么简单。
讨论的内容是关于操作系统的工作方式以及不同操作系统的工作方式不同,但我认为一般而言,以下内容可能适用于所有现代* nixes。
首先,“加载到内存中”是一个模棱两可的短语;实际上,我们所指的是将其虚拟地址空间映射到内存中。这很重要,因为“虚拟地址空间”是指可能需要放置到内存中的内容,但实际上并不是一开始:实际加载到内存中的大部分是地图本身 -而不是地图。 “区域”将是磁盘(或磁盘高速缓存)上的可执行文件,实际上,当您调用可执行文件时,其中的大部分可能未加载到内存中。
同样,“领土”的大部分是对其他领土(共享库)的引用,同样,仅因为已提及它们并不意味着它们也已真正加载。在实际使用它们之前,不会加载它们,然后只有真正需要加载的部分才能成功进行“使用”。
例如,这是top
在Linux上引用bash
实例的代码片段:
VIRT RES SHR S %CPU %MEM TIME+ COMMAND
113m 3672 1796 S 0.0 0.1 0:00.07 bash
113 MB VIRT是虚拟地址空间,映射到RAM中。但是RES是该进程实际消耗的RAM数量-只有3.7 kB。其中,有些是上述共享区域的一部分-1.8 kB SHR。但是我/bin/bash
的磁盘容量为930 kB,它链接到(共享库)的基本libc大小又增加了一倍。
该shell现在什么也没做。假设我调用了一个内置命令,我们之前说过该命令已经与外壳的其余部分一起“装入了内存”。内核从映射中的某个点开始执行涉及的所有代码,当内核到达尚未真正加载的代码的引用时,即使从磁盘上的可执行映像加载,它也会从磁盘上的可执行映像加载它。从某种意义上说,该可执行文件(无论是外壳程序,独立工具还是共享库)已经“加载到内存中”。
这称为需求分页。
我做了以下实验,以表明内置命令实际上是作为exectuable的一部分加载的bash
。因此,为什么将它们称为内置函数,但演示始终是证明某些东西的最佳方法。
启动一个新的bash
shell,并记下其进程ID(PID):
$ bash
$ echo $$
6402
在第二个终端中,运行ps
命令,以便我们可以观察并查看是否bash
开始占用任何额外的内存:
$ watch "ps -Fp 6402"
输出看起来像这样:
Every 2.0s: ps -Fp 6402 Sat Sep 14 14:40:49 2013
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
saml 6402 6349 0 28747 6380 1 14:33 pts/38 00:00:00 bash
注意:内存使用情况在此处的SZ和RSS列中显示。
开始在外壳程序中运行命令(pid 6402):
在您cd
周围时,您会发现实际上内存确实增加了,但这不是因为可执行文件cd
已加载到内存中,而是因为磁盘上的目录结构已加载到内存中。如果继续cd
进入其他目录,则会看到它不断增加。
Every 2.0s: ps -Fp 30208 Sat Sep 14 15:11:22 2013
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
saml 30208 6349 0 28780 6492 0 15:09 pts/38 00:00:00 bash
您可以像这样进行更复杂的测试:
$ for i in `seq 1000`; do cd ..; cd 90609;done
此命令将执行cd一级操作,然后再下回到目录90609 1000次。运行此程序时,如果您在ps
窗口中监视内存使用情况,则会注意到它没有改变。在运行类似的程序时,不应注意到额外的内存使用情况。
痕迹
这又表明我们正在处理内置函数bash
而不是实际的可执行文件。尝试运行时,strace cd ..
您会收到以下消息:
$ strace cd ..
strace: cd: command not found