web-dev-qa-db-ja.com

Windowsサービスによって生成できる子プロセスの最大数を増やす方法-デスクトップヒープ制限

Q:多くの子プロセスを生成するWindowsサービスがあります。プロセスを起動できない制限が100前後あるようです。 CreateProcess()呼び出しはpidで返されますが、プロセスはマテリアライズに失敗します。代わりにサーバーをコンソールアプリケーションとして実行すると、この制限はなくなります。また、DETACHED_PROCESSフラグを設定すると、この制限は2倍以上になります。ただし、DETACHED_PROCESSを設定してCreateProcesssWithLogonW()を呼び出すと、失敗します。

19
Wheezil

これは「デスクトップヒープ」の問題です。非常に良い議論がここにあります:

デスクトップヒープの概要

このonlyは、サービスとして実行されているプログラムに適用されることに注意してください。これは、サービスのデフォルトのデスクトップヒープサイズがアプリケーションのそれよりもはるかに小さいためです。

私たちの場合、変更なしでリソースが不足する前に、約100の子プロセスを起動することができました。この変更により、この数を大幅に増やすことができます。

これは、ナレッジベースでエンドユーザーに提供した回答です。

警告:これはallサービスのデスクトップヒープに影響します!必要以上に大きくしないでください。システムをプッシュしてより多くのリソースを消費し、使用可能なデスクトップヒープの合計サイズの問題にぶつかる可能性があります。

非常に大きなRAMサーバーでも、合計で約100を超えるプロジェクトを開くことができない場合は、Windowsの「デスクトップヒープサイズ」の制限に達した可能性があります。

問題は、(サービスが実行される)ウィンドウの下のサービスセッションでは、ウィンドウの作成に使用できるこの「デスクトップヒープ」スペースが少ないことです。

短いバージョンは次のとおりです。

  • サービスは、インタラクティブセッションよりもデスクトップヒープが小さくなります。

  • デスクトップヒープサイズはウィンドウの数を制限します

  • 各サブサーバーは、表示されていない場合でも1つ以上の「ウィンドウ」を作成します。

解決:

  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

2番目の数値(20480)は、インタラクティブセッションのサイズです。 3番目の数値(768)は、非対話型(サービス)セッションのサイズです。 3番目の数値が2番目の数値の26分の1であることに注意してください。実験的に、これを次のように変更することがわかりました。

SharedSection=1024,20480,2048

プロジェクトの制限を106から270に増やし、ヒープサイズにほぼ完全に合わせてスケーリングしました。システム上のすべてのユーザーが同時に開くと予想されるプロジェクトの最大数を反映する値を選択してください。システム内の各サービスはより多くの貴重なリソースを消費するため、この値を必要以上に大きくしたり、8192以下にしたりしないでください。

これらの新しい設定を有効にするには、再起動する必要があります。

25
Wheezil

これをテストするために必要なリモートデスクトップサーバーが多数あったため、ADにRDサーバーを照会してこのレジストリの変更を適用するPowerShellスクリプトを作成しました。楽しい

   $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" 
            }       
        }
    }
}
1
Shaun