如何增加Windows服务可以产生的subprocess的最大数量 – 桌面堆栈限制

问:我有一个产生大量subprocess的Windows服务。 似乎有一些限制,大约100,无法启动过程。 CreateProcess()调用返回一个pid,但是这个过程只是无法实现。 如果我将服务器作为控制台应用程序运行,则此限制将消失。 另外,如果我设置了DETACHED_PROCESS标志,这个限制是双倍的。 但是,如果我设置DETACHED_PROCESS并调用CreateProcesssWithLogonW(),则会失败。

Solutions Collecting From Web of "如何增加Windows服务可以产生的subprocess的最大数量 – 桌面堆栈限制"

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

桌面堆概述

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

在我们的情况下,我们能够在没有变化的情况下耗尽资源之前启动大约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,因为系统中的每个服务将消耗更多的宝贵资源。

我们有很多我们需要测试的远程桌面服务器,所以我们编写了一个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\modulees\ActiveDirectory\ActiveDirectory.psm1) { Import-modulee 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-modulee 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" } } } }