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

时间:2020-03-05 18:48:48  来源:igfitidea点击:

我听说在Windows机器上创建一个新进程比在Linux上花费更大。这是真的?有人可以解释为什么价格更高的技术原因,并提供这些原因背后的设计决策的历史原因吗?

解决方案

回答

Unix有一个" fork"系统调用,该系统调用将当前进程"拆分"为两个,并为我们提供与第一个进程相同的第二个进程(对fork调用的返回进行模运算)。由于新进程的地址空间已经启动并运行,因此它比在Windows中调用'CreateProcess'并加载exe映像,关联的dll等便宜。

在分叉的情况下,OS可以对与这两个新进程相关联的内存页面使用"写时复制"语义,以确保每个用户都获得他们自己随后修改的页面的副本。

回答

除了Rob Walker的答案:
现在,我们可以根据需要拥有诸如Native POSIX Thread Library之类的东西。
但是很长一段时间以来,在unix世界中"委托"工作的唯一方法是使用fork()(在许多情况下,它仍然是首选)。
例如某种套接字服务器

socket_accept()
fork()
if (child)
    handleRequest()
else
    goOnBeingParent()

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

回答

我认为,这件事的关键是两个系统的历史用法。 Windows(以前是DOS)最初是个人计算机的单用户系统。因此,这些系统通常不必始终创建很多进程。 (非常)简单地说,只有在这个孤独的用户请求时才会创建一个流程(相对而言,我们人类的运行速度并不快)。

基于Unix的系统最初是多用户系统和服务器。特别是对于后者,让进程(例如mail或者http守护程序)分开处理以处理特定作业(例如照顾一个传入连接)的情况并不少见。执行此操作的一个重要因素是廉价的" fork"方法(如Rob Walker(47865)所述,最初为新创建的进程使用相同的内存),该方法非常有用,因为新进程立即拥有所有信息。需求。

显然,至少从历史上看,基于Unix的系统具有快速的进程创建的需求远远大于Windows系统。我认为情况仍然如此,因为基于Unix的系统仍然非常面向过程,而Windows由于其历史悠久,可能更多地面向线程(线程对于响应式应用程序很有用)。

免责声明:我绝不是这个问题的专家,如果我理解错了,请原谅我。

回答

mweerden:从第一天开始,NT就已为多用户设计,因此这并不是真正的原因。但是,我们对的是,进程创建在NT上的作用不如在Unix上重要,因为与Unix相比,NT与Unix相比,主张多线程而不是多处理。

Rob,确实,使用COW时fork相对便宜,但事实上,fork后面紧跟着一个执行程序。执行人员也必须加载所有图像。因此,讨论前叉的性能只是事实的一部分。

在讨论进程创建的速度时,最好区分NT和Windows / Win32. 就NT(即内核本身)而言,我认为进程创建(NtCreateProcess)和线程创建(NtCreateThread)不会比一般Unix显着慢。可能还有更多事情要做,但是我看不出性能差异的主要原因。

但是,如果我们查看Win32,我们会注意到它会增加很多创建过程的开销。首先,它要求CSRSS通知有关过程创建的过程,这涉及LPC。它至少需要另外加载kernel32,并且必须执行许多其他簿记工作项,然后才能将该进程视为完整的Win32进程。而且,我们不要忘记解析清单所带来的所有额外开销,检查映像是否需要兼容性填充程序,检查软件限制策略是否适用(yada yada)。

也就是说,除了原始创建进程,VA空间和初始线程之外,我还看到所有必须做的小事情的总和总体下降。但是,正如开头所说的那样,由于多线程而不是多任务的支持,唯一受此额外费用严重影响的软件是移植性差的Unix软件。尽管当Chrome和IE8之类的软件突然重新发现多处理的优势并开始频繁启动和拆卸过程时,这种情况发生了变化。

回答

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

回答

嗯,似乎有很多"这样更好"的理由。

我认为人们可以从阅读" Showstopper"中受益。关于Windows NT开发的书。

在Windows NT上,服务在一个进程中以DLL的形式运行的全部原因是,它们作为单独的进程太慢了。

如果我们摔倒了,会发现库加载策略是问题所在。

实际上,在Unices上,共享库(DLL)的代码段实际上是共享的。

Windows NT会为每个进程加载DLL的副本,因为它会在加载后操纵库代码段(和可执行代码段)。 (告诉我们数据在哪里?)

这导致库中的代码段不可重用。

因此,NT进程创建实际上非常昂贵。不利的一面是,它使DLL没有明显的内存节省,但有可能导致应用程序间的依赖关系问题。

有时,退一步说"现在,如果我们要设计出真正吸引人的东西,那会是什么样子呢?"

我曾经使用过一种非常有气质的嵌入式系统,有一天看着它,发现它是一个腔磁控管,而电子器件位于微波腔中。在那之后,我们使它变得更加稳定(而不像微波炉)。

回答

JP补充说:该过程的大部分开销属于Win32启动。

Windows NT内核实际上确实支持COW fork。 SFU(用于Windows的Microsoft UNIX环境)使用它们。但是,Win32不支持fork。 SFU进程不是Win32进程。 SFU与Win32正交:它们都是基于同一内核构建的环境子系统。

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

Win32运行时库(kernel32.dll等)在启动时还会执行很多注册表读取和初始化操作,这些操作不适用于UNIX,SFU或者本机进程。

本机进程(没有环境子系统)创建起来非常快。 SFU在创建过程方面比Win32少得多,因此它的过程创建起来也很快。

回答

简短的答案是"软件层和组件"。

Windows SW体系结构具有Unix上不存在或者在Unix内核内部进行了简化和处理的几个添加层和组件。

在Unix上,fork和exec是对内核的直接调用。

在Windows上,不直接使用内核API,它上面没有win32和某些其他组件,因此进程创建必须经过额外的层,然后新进程必须启动或者连接到这些层和组件。

一段时间以来,研究人员和公司试图以一种模糊的相似方式来破坏Unix,通常将他们的实验基于Mach内核。但是,每次尝试时,它都会变得如此缓慢,最终导致它们至少部分地永久性地或者用于生产时,至少部分地合并到内核中。