背景
去年我编写了一个便携式博客/网络服务器系统,可以从闪存驱动器运行。它很棒,运行良好,尤其是在 XP 上。问题是,当它在 Windows 7 中运行时,每个控制台程序都会生成二进程、进程本身以及的副本conhost.exe
。
问题
对于便携式博客系统来说,它的每个服务器组件(MySQL 的mysqld.exe
、Apache 的二的实例httpd.exe
、VisualSVN 的两个实例visualsvnserver.exe
和 PHP 的多个实例php-cgi.exe
)生成一个实例conhost.exe
。此时(没有php-cgi.exe
活动的副本,我有五个conhost.exe
正在运行的实例,几乎不占用任何 CPU 周期,但消耗了 22MB 内存(除了实际进程当前正在使用的 80MB)。
研究
自从 Windows 7 发布以来(我想可能从 Vista 开始),我曾多次试图弄清楚确切地各种(新)主机进程(例如conhost.exe
、dllhost.exe
和taskhost.exe
)的用途是什么,以及它们是否真的有必要。我尝试过终止它们,发现控制台程序继续工作,无论是使用控制台窗口的程序,还是不使用控制台窗口的程序(如服务器)。
我已经熟悉了整个csrss.exe
⇨ Windows Vista ⇨conhost.exe
并且看到了同样的情况(几乎一字不差)解释无数次。问题是每个人都只是复制粘贴相同的解释,这毫无帮助。它只是说在 XP 中,控制台应用程序“托管于”或“在...下运行” csrss.exe
,但在 Windows 7 中,它们被移至...conhost.exe
以保证安全。安全方面是有道理的,但它没有说明托管它意味着什么,为什么/何时需要它(或者如果没有必要,是否可以避免它)。即使是 Raymond Chen 的讨论在这个问题上掩盖了为什么控制台应用程序的托管方式完全不同。
我能找到的最接近详细技术解释的是微软博客文章这似乎强化了这样的想法:它只是关于控制台应用程序的 GUI 和窗口。这让我更加怀疑,conhost.exe
对于像这些服务器这样的无窗口程序来说,是否有必要。如果根本没有窗口,那么我为什么要浪费资源,用不必要的进程来扰乱进程空间?为什么 Windows 不能检测出什么时候是不必要的,并避免它?SecurityMatt 的回复在技术解释方面也稍微有用,但同样,没有足够的信息来提供我想要的信息。
我不是唯一一个试图找到一种方法来阻止不必要的事件的人conhost
。这个人询问是否可以禁用它,并被告知“这是不可能的”,没有进一步的努力或考虑。休·D和“几乎不算什么特色”指出了众多冗余实例的问题conhost
(至少在 中csrss
,只有一个副本在运行),包括资源使用情况和子进程结束后的残留实例。我劳弗质疑是否/何时有必要。
观察和解决尝试
如果它们实际上并非始终必不可少(再次说明,我还没有看到关闭它们会产生任何不良影响),那么我想我可以(非常恼人地)通过用批处理文件替换服务器来解决这个问题,这些批处理文件运行服务器,等待,然后关闭conhost
它们导致运行的副本。当然,这需要一种快速简便的方法来确定是哪一个。堕落游戏R询问如何获取与给定 PID 的控制台程序关联的实例conhost.exe
,但没有得到答案。我认为只需检索父进程的 PID 就可以了(不,ProcessExplorer 不是一个选项,一个自动化/可脚本化解决方案是必需的),但这不仅需要创建某种框架来获取子进程的 PID(而不是简单地运行它并完成任务),而且还意味着找出一种方法使其与 XP 兼容(例如,检查父进程的映像名称)。本博客帖子提供了一种方法,但它需要 PowerShell,而且并不理想,更不用说它没有提到运行脚本的后果。
问题)
也许微软认为没有人再使用命令提示符(*咳嗽*Windows 8*咳嗽*)因此认为给他们增加负担不是什么大问题,但确实存在多个控制台应用程序正在运行的情况,并且每个应用程序都会产生一个额外的、消耗内存的、使用 PID 的进程,这很糟糕,而尝试解决这个问题,充其量是极其不方便的。
有人对此事有明确、权威的信息吗?同样,我已经阅读了一般性的解释;我想知道:
- 为什么控制台应用程序必须(仍然)以完全不同的方式处理
- 在什么具体情况下需要具有
conhost
- 什么结果是杀戮
conhost
- 是否有任何方法可以阻止/防止/禁用/阻止它,或者至少有一种简单的方法可以快速处理它?
答案1
控制台应用程序必须以不同的方式处理,因为在 NT 内核(2000、XP、Vista、Windows 7 和 Windows 8 的基础)下,它们是二等公民。在 Unix 系统架构中,每个进程在创建时都附加有标准输入、输出和错误流;终端 IO 是根据这些流实现的(来自键盘的标准输入,以及前往终端的标准输出/错误),如果进程不希望使用这些流或打开它们的文件描述符,则需要付出额外的努力。
在 Windows NT 架构中,虽然它不是 VMS 的直系后代,而且是由差不多同一个团队开发的,但情况正好相反;默认情况下,新生成的进程根本没有与之连接的 I/O 流,也没有“终端”的概念。希望以更接近 Unix 的方式运行的程序可以请求(通过编译时声明)系统为其创建一个控制台窗口以及与之连接的输入/输出流;系统会这样做,但由于 Windows 与 Unix 不同,不会免费为您提供终端,因此需要付出大量额外的努力才能创建一个终端,因此以前是
csrss.exe
,现在是conhost.exe
。至于两者之间的区别,您的“几乎不是一个功能”链接已经充分解释了这一点;简而言之,它的存在是为了解决 Windows 高度隐秘的控制台 API 的上一个版本中的安全漏洞,该漏洞允许在 Windows 7 之前的 NT 版本中提升权限。(仅供参考,Vista 没有
conhost.exe
,这与其作为 NT 家族的 Windows Millennium 的地位相称。)任何想要相当于 Unix stdin/stdout/stderr 的程序都需要一个控制台,因此需要一个 实例
conhost.exe
。来自 Unix 领域的移民,例如 Apache、PHP 等,会需要这些流,因此系统会自动conhost.exe
为它们实例化 ,无论它们是否实际显示窗口。理论上,可以修改 Apache 等程序的源代码,使其不需要终端,并将其编译为 Windows GUI 应用程序而不是控制台应用程序,这样系统就不会觉得有必要为其生成conhost.exe
。假设在实践中也是可能的,似乎没有人足够关心这样做。也许你会是第一个。终止给定进程
conhost.exe
几乎肯定会禁用该实例下正在运行的任何进程的控制台 IO。您可能不关心这一点,因为您正在处理的服务器进程无论如何都不会在控制台 IO 流上执行任何有趣的操作,因此可能没有理由不终止它们的conhost.exe
进程。如果有疑问,请终止它们并查看是否破坏了任何东西。conhost.exe
当启动请求控制台 IO 的程序时,没有办法阻止 Windows 实例化;唯一的方法是重新编译它,这样 Windows 就不会将其视为控制台应用程序。但是,假设终止给定服务器进程的父进程conhost.exe
不会以您关心的任何方式损害其功能,您应该能够通过发出taskkill /f /im conhost.exe
运行提示或控制台窗口一次性终止它们——最好是前者,因为后者可能会死亡,并且几乎肯定会停止工作,只要它的父conhost.exe
实例被终止。同样,如果有疑问,请终止它们并查看是否破坏了任何东西。
答案2
控制台应用程序启动时DETACHED_PROCESS
标志确实会获得控制台或 conhost 子进程。问题是该标志不适用于孙子进程,因此它只适用于您直接启动的进程(如果您能找到允许您指定此标志的实用程序)。
另一个可能有效的选项是控制台进程调用FreeConsole()
功能。一些服务器应用程序支持 -d 或 -detach 参数,但这在 *nix 系统上可能更常见...
答案3
可能对您有用的快速解决方案。链接应用程序时,将 /SUBSYSTEM:WINDOWS 添加到选项中。您还可以使用 editbin.exe 来修改现有的可执行文件。
这会阻止 Windows 为您的应用程序生成 conhost.exe。