Windows XP上的Git sh.exe进程分叉问题,速度慢?

8

Git对我的工作流程至关重要。我在装有3GB RAM的四核机器上运行Windows XP上的MSYS Git,通常它很灵敏和迅速。

突然出现了一个问题,从Git Bash命令提示符中运行任何命令,包括lscd都需要超过30秒的时间。有趣的是,从bash提示符中看起来ls运行得相当快,我可以看到ls的输出,但是它需要大约30秒才能返回提示符。如果我切换到Windows命令提示符(通过从开始菜单运行cmd),git相关命令也需要很长时间才能运行。例如,git status在任何事情发生之前可能需要接近一分钟的时间。有时进程根本无法完成。

请注意,我安装了“MSYS Git”以及常规的“MSYS”用于诸如MinGWmake之类的东西。

我认为问题与位于C:\Program Files\Git\binsh.exe有关。当我从bash提示符中运行ls,或者从windows提示符中调用git时,任务管理器会显示最多四个出现和消失的sh.exe进程。

在这里,我正在等待ls返回,您可以看到任务管理器运行了git.exe和四个实例的sh.exe

Here I am waiting for ls to return and you can see the task manager has git.exe running and four instances of sh.exe

如果我在ls进行中按下ctrl-c,有时会出现包含以下内容的错误:

sh.exe": fork: Resource temporarily unavailable
      0 [main] sh.exe" 1624 proc_subproc: Couldn't duplicate my handle<0x6FC> fo
r pid 6052, Win32 error 5
sh.exe": fork: Resource temporarily unavailable

或者对于 git status 命令: $ git status
sh.exe": fork: Resource temporarily unavailable
sh.exe": fork: Resource temporarily unavailable
sh.exe": fork: Resource temporarily unavailable
sh.exe": fork: Resource temporarily unavailable

我可以修复这个问题,让git再次快速运行吗?如果可以,怎么做?

我尝试过以下方法:

  • 重启
  • 将MSYS Git升级到最新版本,并重新启动
  • 将MSYS升级到最新版本,并重新启动
  • 卸载MSYS和仅卸载并重新安装MSYS Git,并重新启动

我非常希望不要抹掉我的计算机并重新安装Windows,但如果无法解决问题,我将这样做。如果运行 git status cd 需要超过30秒,我将无法编写代码。


你尝试过这些非常相似的问题的答案吗?Git/Bash在Windows 7 x64上极其缓慢Msysgit bash在Windows 7上非常缓慢 - Greg Hewgill
@Greg:我看到了那些问题,但解决方案是针对Windows 7的,所以我无法尝试,因为我使用的是Windows XP。 - AndyL
如果你看到了那些问题,你就会看到$PS1='$ '选项,这是其中一个答案。 - manojlds
啊,我现在明白了。我想我只是仔细检查了被标记为正确答案和其他得到赞同的答案。所有这些确实都是针对Windows 7的解决方案。 - AndyL
这些答案似乎都没有明确提到分叉错误。我也遇到了这个问题(是的,在这台工作电脑上,Git非常慢)。 - Drew Noakes
6个回答

7
通常情况下,当一个程序需要30秒才能完成本应瞬间完成的任务时,更可能是I/O超时问题,通常是网络问题,而不是您的CPU速度或RAM容量的问题。您可能会想知道网络如何参与其中,但这是一个合法的问题(我也不知道您的系统情况)。
Msysgit安装了一个特殊的提示符,运行一个特殊的函数__git_ps1,在提示符中显示一些有用的信息。您可以使用echo $PS1查看此内容,在我的系统中显示如下:
$ echo $PS1
\[\033]0;$MSYSTEM:\w\007 \033[32m\]\u@\h \[\033[33m\w$(__git_ps1)\033[0m\] $

这些额外信息完全是可选的,您可以关闭它。因此,请在Msysgit窗口中尝试以下操作:

$ PS1='$ '
$

这将重置提示符为默认的$,并且不会尝试运行提示符内部的任何命令。如果这解决了您的延迟问题,则很可能是__git_ps1函数造成的。请尝试手动运行它:
$ __git_ps1
 (master)

并查看返回所需的时间。

你可以通过从C:\Program Files\Git\etc\profile中删除调用__git_ps1的行来解决此问题:

#Comment the lines below
#PS1='\[\033]0;$MSYSTEM:\w\007
#\033[32m\]\u@\h \[\033[33m\w$(__git_ps1)\033[0m\]
#$ '

@manojids:进一步检查后,从Windows命令提示符中仅运行git的速度很快。但是从提示符中运行git statusgit anything则很慢。在我运行这些命令之后,即使仅运行git也会变得很慢。我现在正在检查Greg的答案。 - AndyL
无论如何,这个修复程序不会有任何帮助,因为它与cmd完全无关。 - manojlds
@manojlds:我同意这很奇怪。从cmd运行git status仍然很慢。也许即使它们只是从cmd调用,git也可以调用在sh.exe中运行的其他进程? - AndyL
基本上,您遇到了一个问题,通过取消设置PS1来减轻问题的严重程度。Git不是本地Windows应用程序,因此我希望它使用sh.exe。 - manojlds
2
好的!我对你的答案进行了编辑,指出你可以通过在 C:\Program Files\Git\etc\profile 中注释掉相应的行来解决问题。非常感谢你的帮助。 - AndyL
显示剩余3条评论

7

我们也遇到了这个问题,我认为最终追踪到了msys对Windows安全模型的实现。我将尝试发布一个短小的问题摘要:

屏幕截图: stuck sh.exe的堆栈跟踪。请注意,当msys-1.0.dll调用NetServerEnum()时

这就是sh.exe被阻塞30秒钟时正在发生的情况。因此,NetServerEnum()只在msys中的一个地方调用,即get_lsa_srv_inf()中的security.cc:228,该函数由get_logon_server()get_logon_server_and_user_domain()调用,在create_token()中调用,该函数由syscalls.cc中的seteuid()调用,该函数由setuid()调用。

因此,发生的情况是当msys DLL被初始化并且sh.exe尝试调用setuid()时,msys试图忠实遵守Windows安全模型,并尝试从您的域/工作组查找域服务器列表。不幸的是,与Linux不同,在Windows中,这是一个阻塞调用,需要5-30秒才能完成/超时,并且实际上对于git来说相当不必要。
我们的解决方案是通过在winsup.cc中将has_security设置为false来创建新的msys.dll以禁用安全“功能”。随msysgit一起提供的bash/sh.exe与我们的新版本的msys.dll不兼容,因此我们不得不从头开始编译新的bash.exe,不知道为什么。最终结果是sh.exe不再尝试进行这些NetServerEnum调用,并且运行速度非常快。

3
如果同时运行多个Git命令时出现减速,可能是msysgit内核锁定问题导致的。我们发现,在某些情况下,多个git.exe实例都会等待同一个内核对象(在WaitForSingleObject()中),这实际上意味着在系统上只能运行一个git命令。请参见此处:10 git.exe processes all waiting on a single kernel object。使用ProcessExplorer,我们可以看到所有的git.exe进程都卡在这里:
ntoskrnl.exe!KeWaitForMultipleObjects+0xc0a
ntoskrnl.exe!KeAcquireSpinLockAtDpcLevel+0x732
ntoskrnl.exe!KeWaitForMutexObject+0x19f
ntoskrnl.exe!FsRtlCancellableWaitForMultipleObjects+0x5e
ntoskrnl.exe!FsRtlCancellableWaitForSingleObject+0x27 

这似乎与这个问题有关:http://code.google.com/p/msysgit/issues/detail?id=320因为它不是Git的问题,而是伪Linux运行时(mingw)似乎包含了这个问题。
我们将用于运行应用程序的用户帐户从SYSTEM更改为交互式用户帐户,内核对象的等待就消失了:
健康的git.exe进程 git.exe processes spawning happily 因此,你所看到的减速可能与某种内核对象争用有关——只有在前一个git命令释放内核锁之后,其他命令才能运行。
尝试更改运行git命令的用户帐户,并查看是否解决了该问题-对我们来说确实如此。

2
尽管Greg的回答解决了速度问题,但我认为这只是掩盖了问题,而没有解决它。
我开始遇到git bash运行缓慢的问题,并按照Greg描述的步骤确定了__git_ps1是罪魁祸首。
与其修改命令提示符信息(我发现它显示的信息很有用),我找到了一个适合我的解决方案,详见博客文章: 作为域用户登录时解决Git bash缓慢的方法

在网上搜索了一下,我发现git使用默认的home目录, 而我的账户设置为网络账户。这意味着git会一直在这个目录中查找,导致延迟。

为了解决这个问题,我创建了一个本地用户环境变量,覆盖了默认值,并将其设置为%USERPROFILE%,它指向c:\users[username]。

同样的解决方案也发布在了SO上,回答了类似的问题
将环境变量添加到全速返回的 git 中,我仍然可以获得命令行信息。

0
如果在NetServerEnum中枚举登录服务器时出现挂起的情况,请尝试将LOGONSERVER环境变量设置为实际的登录服务器。

0
我在Windows XP机器上遇到了进程分叉缓慢的问题。有时一个进程分叉需要几分钟时间。
对我来说解决方法是清空计算机的TEMP文件夹。这台计算机是共享资源,多年来已经积累了很多文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接