Why is creating a new process more expensive on Windows than Linux?我听说在Windows机器上创建一个新进程比在Linux上更昂贵。 这是真的? 有人可以解释为什么它更昂贵的技术原因,并为这些原因背后的设计决策提供任何历史原因? mweerden:NT从第一天开始就是为多用户设计的,所以这不是真正的原因。但是,你肯定的是,在Unix上,进程创建在NT上比在Unix上扮演一个不太重要的角色,与Unix相反,它支持多线程而不是多处理。 Rob,使用COW时叉子确实相对便宜,但事实上,fork主要是一个exec。并且exec也必须加载所有图像。因此,讨论fork的性能只是事实的一部分。 在讨论创建进程的速度时,区分NT和Windows / Win32可能是一个好主意。至于NT(即内核本身),我认为进程创建(NtCreateProcess)和线程创建(NtCreateThread)并不像普通Unix那样慢得多。可能会有更多的事情发生,但我没有看到这里性能差异的主要原因。 但是,如果你看一下Win32,你会注意到它为进程创建增加了相当多的开销。首先,它要求CSRSS通知涉及LPC的流程创建。它至少需要加载kernel32,并且在将该进程视为完整的Win32进程之前,它必须执行许多额外的簿记工作项。让我们不要忘记解析清单所带来的所有额外开销,检查图像是否需要兼容性垫片,检查软件限制策略是否适用,yada yada。 也就是说,除了原始创建流程,VA空间和初始线程之外,我还看到了所有必须完成的小事情总和的整体放缓。但正如开头所说 - 由于多线程优于多任务处理,唯一受此额外费用影响的软件是移植不良的Unix软件。虽然当Chrome和IE8等软件突然重新发现多处理的好处并开始频繁启动和拆卸流程时,这种情况会发生变化...... Unix有一个'fork'系统调用,它将当前进程"拆分"为两个,并为你提供第二个进程,它与第一个进程相同(以fork调用返回为模)。由于新进程的地址空间已经启动并运行,因此应该比在Windows中调用'CreateProcess'并使其加载exe映像,关联的dll等更便宜。 在fork情况下,OS可以对与两个新进程相关联的内存页使用"copy-on-write"语义,以确保每个进程都获得自己随后修改的页面副本。 添加到JP所说的:大部分开销都属于Win32启动过程。 Windows NT内核实际上支持COW fork。 SFU(Microsoft的Windows UNIX环境)使用它们。但是,Win32不支持fork。 SFU进程不是Win32进程。 SFU与Win32正交:它们都是在同一内核上构建的环境子系统。
除了对 Win32运行时库(kernel32.dll等)也在启动时执行大量注册表读取和初始化,这些不适用于UNIX,SFU或本机进程。 本机进程(没有环境子系统)创建速度非常快。 SFU在创建流程方面比Win32少得多,因此其流程也很快创建。 更新2019年:添加LXSS:适用于Linux的Windows子系统 替换SFU for Windows 10是LXSS环境子系统。它是100%内核模式,不需要Win32继续拥有的任何IPC。这些进程的Syscall直接指向lxss.sys / lxcore.sys,因此fork()或其他创建调用的进程只需要为创建者进行1次系统调用,总计。 [称为实例的数据区]跟踪所有LX进程,线程和运行时状态。 LXSS进程基于本机进程,而不是Win32进程。所有Win32特定的东西,如兼容性引擎都没有参与。
除了Rob Walker的答案:
因此,fork的实现必须很快,并且随着时间的推移已经实现了很多优化。 我认为,这个问题的关键是两个系统的历史用法。 Windows(以及之前的DOS)最初是个人计算机的单用户系统。因此,这些系统通常不必一直创建大量进程; (非常)简单地说,只有当这个孤独的用户请求它时才创建一个进程(而且我们人类相对来说操作速度不是很快)。
基于Unix的系统最初是多用户系统和服务器。特别是对于后者,具有分离进程以处理特定作业(例如,处理一个传入连接)的进程(例如,邮件或http守护进程)并不罕见。这样做的一个重要因素是廉价的 很明显,至少从历史上看,基于Unix的系统对快速创建流程的需求远远大于Windows系统。我认为情况仍然如此,因为基于Unix的系统仍然是面向流程的,而Windows由于其历史,可能更多地面向线程(线程对于生成响应式应用程序很有用)。 免责声明:我不是这方面的专家,如果我弄错了,请原谅我。 简短的回答是"软件层和组件"。 Windows SW体系结构有一些额外的层和组件,这些层和组件在Unix上不存在,或者在Unix内核中进行了简化和处理。 在Unix上,fork和exec是对内核的直接调用。 在Windows上,内核API不是直接使用的,它上面有win32和某些其他组件,因此创建进程必须经过额外的层,然后新进程必须启动或连接到这些层和组件。 很长一段时间以来,研究人员和企业都试图以模糊的方式分解Unix,通常是将他们的实验基于Mach内核;一个众所周知的例子是OS X ..但是,每当他们尝试时,它变得如此缓慢,他们最终至少部分地将这些部分合并到内核中,无论是永久性还是生产出货。 呃,似乎有很多"这种方式更好"的理由正在进行中。 我认为人们可以从阅读"Showstopper"中受益;关于Windows NT开发的书。 服务作为DLL在Windows NT上的一个进程中运行的全部原因是它们作为单独的进程太慢。 如果你沮丧和肮脏,你会发现库加载策略是问题所在。 在Unices(通常)上,共享库(DLL)的代码段实际上是共享的。 Windows NT在每个进程中加载??DLL的副本,因为它在加载后操作库代码段(和可执行代码段)。 (告诉它你的数据在哪里?) 这导致库中的代码段不可重用。 因此,NT进程创建实际上非常昂贵。并且在不利方面,它使得DLL在内存中没有明显的节省,但是存在应用程序间依赖性问题的可能性。 有时候工程学会退后一步说:"现在,如果我们要把它设计成真的很糟糕,那会是什么样子?" 我曾经使用过一个非常有气势的嵌入式系统,有一天看着它并意识到它是一个腔磁控管,电子器件在微波腔中。之后我们让它变得更加稳定(而不像微波炉)。 因为在某些答案中似乎有一些MS-Windows的理由,例如
现在让我们看看事实,性能有何不同?
数据来自http://www.bitsnbites.eu/benchmarking-os-primitives/。
笔记: 进程创建类型操作的数字(因为很难在图表中看到Linux的值)。 按速度顺序,最快到最慢(数字是时间,小是更好)。
其他测量的数字
值得注意的是,Windows中的安全模型比基于unix的操作系统复杂得多,后者在创建进程时增加了大量开销。多线程的另一个原因是Windows中的多处理优先。 所有这些加上事实是,在Win机器上,很可能一个防病毒软件将在CreateProcess期间启动...这通常是最大的减速。 |