【问题标题】:How to increase the maximum number of child processes that can be spawned by a windows service -- desktop heap limits如何增加 Windows 服务可以生成的子进程的最大数量——桌面堆限制
【发布时间】:2013-07-04 14:06:01
【问题描述】:

问:我有一个生成大量子进程的 Windows 服务。似乎有一些限制,大约 100 个,无法启动该进程。 CreateProcess() 调用返回一个 pid,但随后该过程无法实现。如果我将我们的服务器作为控制台应用程序运行,这个限制就会消失。另外,如果我设置 DETACHED_PROCESS 标志,这个限制会增加一倍以上。但是,如果我设置 DETACHED_PROCESS 并调用 CreateProcesssWithLogonW(),则会失败。

【问题讨论】:

    标签: windows createprocess


    【解决方案1】:

    这是一个“桌面堆”问题。可以在这里找到一个很好的讨论:

    Desktop Heap OverviewDesktop Heap, Part 2

    请注意,这适用于作为服务运行的程序,因为服务的默认桌面堆大小比应用程序小得多。

    在我们的例子中,我们能够在资源耗尽之前启动大约 100 个子进程而无需进行更改。随着变化,这个数字可以大大增加。

    这是我们在知识库中为最终用户提供的答案:

    警告:这会影响 所有 服务的桌面堆!请勿使其大于必要的大小,否则您会推动系统消耗更多资源,并且您可能会遇到可用桌面堆总大小方面的问题。

    如果您发现无法打开超过 100 个项目,即使在非常大的 RAM 服务器上,您也可能遇到了 Windows“桌面堆大小”的限制。

    问题在于 windows 下的服务会话(服务运行的地方)具有较少的“桌面堆”空间可用于创建窗口。

    简短的版本是:

    • 服务获得的桌面堆比交互式会话小。

    • 桌面堆大小限制窗口数量

    • 每个子服务器都会创建一个或多个“窗口”,即使我们看不到它们。

    解决方案:

    1. 在进行任何更改之前备份您的注册表!

    2. 以管理员身份运行 regedit.exe

    3. 编辑注册表值:

      HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\Windows
      
    4. 你会看到这样的字符串:

      %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16
      

    关键是:

    SharedSection=1024,20480,768
    

    第二个数字 (20480) 是交互式会话的大小。第三个数字 (768) 是非交互式(服务)会话的大小。请注意第三个数字比第二个数字小 26 倍。通过实验,我们发现将其更改为:

    SharedSection=1024,20480,2048
    

    将项目限制从 106 增加到 270,几乎完美地随堆大小缩放。选择一个值,该值反映您希望系统上的所有用户同时打开的最大项目数。不要让这个值大于必要的值,并且不大于 8192,因为系统中的每个服务都会消耗更多的宝贵资源。

    您需要重新启动才能使这些新设置生效。

    【讨论】:

    • 我不懂所有这些似乎适用于分叉服务的“桌面堆”文章中的语言,但这个答案拯救了我们的隐藏。
    • 令人难以置信的是,Windows 2008 Server Web Edition(Vista 核心)、Windows 2008 Server R2(Windows 7 核心)和 Windows 2012 Server R2(Windows 8.1 核心)也受到了同样的限制。我将我的更改为 1024,20480,4096,并将所有这些服务器上的最大线程数从 16 个提高到 32 个,这对资源使用没有任何不良影响,但在这些服务器上运行的服务的能力显着提高,同时成功地产生其他进程。谢谢!
    • +1 以获得非常清晰的描述和解决方法。但是,作为记录,如果您在服务中创建这么多子进程,那么您做错了。 :-) [当然,如果您要从 UNIX 移植代码,那么重新构建它可能不值得。]
    • 哈利,我非常感谢你所说的。不幸的是,我们需要进程级别的隔离,因为我们有一个系统可以连接到用户指定的数据库驱动程序和其他各种质量和稳定性级别的库。我们经历了一个艰难的过程,即试图为每个进程托管多个“项目”会导致各种不良和不可预测的交互。能够杀死一个进程是我们的逃生之门。
    • 链接到文章表明这​​在 Windows Vista 中已全部更改,但我的* Windows 7 Enterprise 机器(我可能遇到类似的问题)具有相同的配置,默认情况下。谁能进一步澄清这里的裂缝是什么? *技术上不是我的。我不是自愿拥有 Windows 机器的。
    【解决方案2】:

    我们需要在许多远程桌面服务器上进行测试,因此我们编写了一个 powershell 脚本来查询我们的 RD 服务器的 AD,然后应用此注册表更改。享受

       $newValue = "%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,2048 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16"
    $origValue = "%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16"
    
    if ($update) {
        Clear-Variable update
    }
    
    $updateConfirm= [System.Windows.Forms.MessageBox]::Show("Update Desktop Heap Limitation to 2048?" , "Status" , 4) 
    if ($updateConfirm -eq "YES" ) {
        $update = $true
    } else { 
        $revertConfirm= [System.Windows.Forms.MessageBox]::Show("Revert Desktop Heap Limitation to 768?" , "Status" , 4) 
        if ($revertConfirm -eq "YES" ) {
            $update = $false
        } 
    }
    
    if (($updateConfirm -ne "YES") -and ($revertConfirm -ne "YES")) {
        Write-Host "User did not specify whether to update or revert Desktop Heap Limitation. Exiting Setup."
        Read-Host "Press Enter to exit."
        break
    }
    
    #Import Active Directory PowerShell module
    if (Test-Path C:\Users\${env:USERNAME}\Documents\WindowsPowerShell\Modules\ActiveDirectory\ActiveDirectory.psm1) {
        Import-Module ActiveDirectory -prefix AD
    } else {
        $s = New-PSSession -computerName DC01WDC01
        Invoke-command { import-module ActiveDirectory } -session $s
        Export-PSSession -session $s -commandname *-AD* -outputmodule ActiveDirectory -allowclobber
        Import-Module ActiveDirectory -prefix AD
        Remove-PSSession -session $s
    }
    
    $servers =  Get-ADADComputer -Filter {(Name -Like "RDS*")}  | Select -Expand Name
    
    foreach ($server in $servers) {
        Write-Host "Working on $server" -ForegroundColor Magenta
        if(!(Test-Connection -ComputerName $server -Count 1 -quiet)) {
            Write-Warning "$server : Offline"
            Continue
        }
    
        if ($update -eq $true) {
            Invoke-Command -ComputerName $server -ArgumentList $newValue -ScriptBlock {
                Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems" -Name "Windows" -Value $args[0]
                $result = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems" | SELECT Windows
                if ($result.Windows -like "*SharedSection=1024,20480,2048*") {
                    Write-Host "Successfully reverted Desktop Heap Limit to 2048" -ForegroundColor Green
                } else {
                    Write-Warning "Update to registry value unsuccessful on $env:ComputerName" 
                }              
            }
        } elseif ($update -eq $false) {
            Invoke-Command -ComputerName $server -ArgumentList $origValue -ScriptBlock {
                Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems" -Name "Windows" -Value $args[0]
                $result = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems" | SELECT Windows    
                if ($result.Windows -like "*SharedSection=1024,20480,768*") {
                    Write-Host "Successfully reverted Desktop Heap Limit to 768" -ForegroundColor Green
                } else {
                    Write-Warning "Update to registry value unsuccessful on $env:ComputerName" 
                }       
            }
        }
    }
    

    【讨论】:

    • 不幸的是,在我们的情况下,该设置对我们不起作用,但也许该脚本可以帮助其他人使用大量机器进行测试。 :)
    • 为我工作,但在进行更改后必须重新启动才能生效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-19
    • 1970-01-01
    • 2020-09-22
    • 2023-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多