为什么在Windows上创建比Linux更昂贵的新流程?

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正交:它们都是在同一内核上构建的环境子系统。

除了对CSRSS的进程外LPC调用之外,在XP及更高版本中还有一个对应用程序兼容性引擎的进程外调用,以便在应用程序兼容性数据库中查找该程序。此步骤导致足够的开销,Microsoft提供了一个组策略选项,以便出于性能原因禁用WS2003上的兼容性引擎。

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的答案:
如今你有像Native POSIX Thread Library这样的东西 - 如果你愿意的话。
但是很长一段时间,在unix世界中"委托"工作的唯一方法是使用fork()(在许多情况下它仍然是首选)。
例如某种套接字服务器

1
2
3
4
5
6
socket_accept()
fork()
if (child)
    handleRequest()
else
    goOnBeingParent()

因此,fork的实现必须很快,并且随着时间的推移已经实现了很多优化。
Microsoft支持CreateThread甚至是光纤,而不是创建新进程和进程间通信的使用。我认为将CreateProcess与fork进行比较并不"公平",因为它们不可互换。将fork / exec与CreateProcess进行比较可能更合适。


我认为,这个问题的关键是两个系统的历史用法。 Windows(以及之前的DOS)最初是个人计算机的单用户系统。因此,这些系统通常不必一直创建大量进程; (非常)简单地说,只有当这个孤独的用户请求它时才创建一个进程(而且我们人类相对来说操作速度不是很快)。

基于Unix的系统最初是多用户系统和服务器。特别是对于后者,具有分离进程以处理特定作业(例如,处理一个传入连接)的进程(例如,邮件或http守护进程)并不罕见。这样做的一个重要因素是廉价的fork方法(如Rob Walker(47865)所述,最初对新创建的进程使用相同的内存),这非常有用,因为新进程立即拥有所有信息需要。

很明显,至少从历史上看,基于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的理由,例如

  • "NT内核和Win32,不是一回事。如果您编程到NT内核那么它就不那么糟了" - 是的,但除非您正在编写Posix子系统,否则谁在乎。你将写入win32。
  • "将fork与ProcessCreate进行比较是不公平的,因为他们做了不同的事情,Windows没有fork" - 的确如此,
    所以我会比较喜欢。但是我也会比较fork,因为它有许多用例,例如进程隔离(例如,Web浏览器的每个选项卡在不同的进程中运行)。

现在让我们看看事实,性能有何不同?

数据来自http://www.bitsnbites.eu/benchmarking-os-primitives/。
因为偏见是不可避免的,所以在总结时,我做的是支持MS-Windows
大多数测试的硬件i7 8核心3.2GHz。运行Gnu / Linux的Raspberry-Pi除外

A comparison of various basic operations, on Gnu/Linux, Apple-Mac, and Microsofts Windows (smaller is better)

A comparison of MS-Windows process create vs Linux

笔记:
在linux上,fork比MS-Window的首选方法CreateThread更快。

进程创建类型操作的数字(因为很难在图表中看到Linux的值)。

按速度顺序,最快到最慢(数字是时间,小是更好)。

  • Linux CreateThread 12
  • Mac CreateThread 15
  • Linux Fork 19
  • Windows CreateThread 25
  • Linux CreateProcess(fork + exec)45
  • Mac Fork 105
  • Mac CreateProcess(fork + exec)453
  • Raspberry-Pi CreateProcess(fork + exec)501
  • Windows CreateProcess 787
  • Windows CreateProcess使用病毒扫描程序2850
  • Windows Fork(使用CreateProcess + fixup进行模拟)大于2850

其他测量的数字

  • 创建文件。

    • Linux 13
    • Mac 113
    • Windows 225
    • Raspberry-Pi(带有慢速SD卡)241
    • 带有防御者和病毒扫描程序等的Windows 12950
  • 分配内存

    • Linux 79
    • Windows 93
    • Mac 152

值得注意的是,Windows中的安全模型比基于unix的操作系统复杂得多,后者在创建进程时增加了大量开销。多线程的另一个原因是Windows中的多处理优先。


所有这些加上事实是,在Win机器上,很可能一个防病毒软件将在CreateProcess期间启动...这通常是最大的减速。


推荐阅读

    linux下看进程命令行?

    linux下看进程命令行?,系统,情况,软件,服务,状态,名称,环境,进程,命令,数据,

    linux进程与磁盘命令?

    linux进程与磁盘命令?,管理,系统,信息,情况,基础,增长,单位,地址,发行,命令,L

    linux的进程管理命令?

    linux的进程管理命令?,系统,实时,工作,管理,命令,地址,名称,进程,服务,基础,l

    linux端口进程命令?

    linux端口进程命令?,系统,情况,地址,网络,信息,状态,灵活,工具,端口,命令,如

    linux进程的命令行?

    linux进程的命令行?,地址,工作,系统,信息,命令,管理,名称,进程,目录,服务,lin

    linux当前进程命令?

    linux当前进程命令?,系统,信息,工作,状态,命令,进程,情况,地址,软件,实时,lin

    linux各种命令的解释?

    linux各种命令的解释?,地址,工作,系统,信息,命令,目录,时间,管理,控制台,常

    linux下杀进程命令?

    linux下杀进程命令?,系统,管理,进程,命令,名称,代码,终端,结束,指令,信号,Lin

    linux关于的进程命令?

    linux关于的进程命令?,系统,进程,管理,命令,名称,代码,软件,信息,定期,状态,l

    linux路径命令解释?

    linux路径命令解释?,系统,信息,设备,数据,工具,命令,文件,标准,发行,时间,lin

    linux终止进程命令键?

    linux终止进程命令键?,系统,管理,进程,软件,暂停,工具,命令,代码,名称,传播,l

    linux向进程发送命令?

    linux向进程发送命令?,通信,地址,系统,时间,工作,信息,管理,状态,进程,数据,l

    linux重启进程号命令?

    linux重启进程号命令?,工作,系统,地址,标准,命令,设备,工具,信息,基础,情况,L

    linux中调度进程命令?

    linux中调度进程命令?,系统,状态,策略,实时,信息,进程,数据,管理,时间,异常,L

    linux检测进程命令?

    linux检测进程命令?,系统,服务,地址,状态,信息,检测,进程,命令,第一,软件,lin

    linux进程中断命令行?

    linux进程中断命令行?,系统,软件,管理,进程,信息,名字,名称,平台,命令,结束,l

    linux进程有关命令?

    linux进程有关命令?,系统,状态,信息,时间,进程,命令,百分比,暂停,名称,定期,L

    linux进程管理命令?

    linux进程管理命令?,系统,管理,地址,工作,状态,进程,信息,时间,基础,命令,Lin

    linux命令流程图工具?

    linux命令流程图工具?,软件,工具,在线,网站,电脑,流程图,网络,名称,系统,首

    linux命令进程占系统?

    linux命令进程占系统?,系统,情况,时间,实时,基础,进程,命令,分析,信息,衍生,L