PoweShellを利用しているとSystem.OutOfMemoryException
の表示にめぐり会う時がきます。
特にGet-ChildItem -Recurse | Select-String hogehoge
などという処理をすると巡り会いやすくなります。
今回は、PowerShellのShellに割り当てられたメモリの調整についてです。
WSMAN: ドライブの調整にあたって前提
Windows PowerShellの諸々調整は、WSMAN:
ドライブで行えます。
以下を調整にあたり注意してください。
- WSMANのパラメータ変更操作には管理者権限が必要なのでご注意ください
- WinRMサービスが動いていることが必要です (Get-Service -Name WinRM)
マシン全体のチューニング
まずはマシン全体の制限を見ましょう。
WSManドライブのlocalhost\Shell
を確認します。
cd WSMan: ls localhost\Shell
調整すべきはMaxMemoryPerShellMB
パラメータです。以下のコードはWSManドライブに移動せずとも確認できます。
デフォルトは1024MBです。
Get-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB
パラメータを調整するにはSet-Item
コマンドレットを利用します。
例えば2048MBに調整するには、次のようにします。
PS> Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 2048 WARNING: The updated configuration might affect the operation of the plugins having a per plugin quota value greater than 2048. Verify the configuration of all the registered plugins and change the per plugin quota values for the affected plugins.
プラグインのチューニング
先の警告の通り、PowerShell 3.0においては、 プラグインのメモリ調整も必要です。
プラグインは色々ありますが、調整すべきはMicrosoft.powershell
です。
PS> ls WSMan:localhost\Plugin WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin Type Keys Name ---- ---- ---- Container {Name=Event Forwarding Plugin} Event Forwarding Plugin Container {Name=microsoft.powershell} microsoft.powershell Container {Name=microsoft.powershell.workf... microsoft.powershell.workflow Container {Name=microsoft.powershell32} microsoft.powershell32 Container {Name=WMI Provider} WMI Provider
以下のコマンドで現在のQuotaを知ることができます。デフォルトのままなら恐らく1000MBと表示されます。
PS> Get-Item WSMan:localhost\Plugin\microsoft.powershell\Quotas\MaxConcurrentCommandsPerShell WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin\microsoft.powershell\Quotas Type Name SourceOfValue Value ---- ---- ------------- ----- System.String MaxConcurrentCommandsPerShell 1000
これもマシン設定と同様に調整します。今回の場合は、2048MBです。
PS> Set-Item WSMan:localhost\Plugin\microsoft.powershell\Quotas\MaxConcurrentCommandsPerShell 2048 WARNING: The configuration changes you made will only be effective after the WinRM service is restarted. To restart the WinRM service, run the following command: 'Restart-Service winrm'
WinRMの再起動による変更の適用
変更を適用するには、WinRMを再起動します。
Restart-Service WinRM
最後に現在値が変更されていることを確認します。
# Machine Configuration Get-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB # Endpoint Plugin Configuration Get-Item WSMan:localhost\Plugin\microsoft.powershell\Quotas\MaxConcurrentCommandsPerShell
ファンクション化
面倒なのでfunctionにしてしまいます。
function Set-PowerShellMemoryTuning{ param( [parameter( position = 0, mandatory = 1)] [ValidateNotNullorEmpty()] [ValidateRange(1,2147483647)] [int] $memory ) # Test Elevated or not $TestElevated = { $user = [Security.Principal.WindowsIdentity]::GetCurrent() (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } if (&$TestElevated) { # Machine Wide Memory Tuning Write-Warning "Current Memory for Machine wide is : $((Get-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB).value) MB" Write-Warning "Change Memory for Machine wide to : $memory MB" Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB $memory # EndPoing Memory Tuning Write-Warning "Current Memory for Plugin is : $((Get-Item WSMan:localhost\Plugin\microsoft.powershell\Quotas\MaxConcurrentCommandsPerShell).value) MB" Write-Warning "Change Memory for Plugin to : $memory MB" Set-Item WSMan:localhost\Plugin\microsoft.powershell\Quotas\MaxConcurrentCommandsPerShell $memory # Restart WinRM Write-Warning "Restarting WinRM" Restart-Service WinRM -Force -PassThru # Show Current parameters Write-Warning "Current Memory for Machine wide is : $((Get-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB).value) MB" Write-Warning "Current Memory for Plugin is : $((Get-Item WSMan:localhost\Plugin\microsoft.powershell\Quotas\MaxConcurrentCommandsPerShell).value) MB" } else { Write-Error "This Cmdlet requires Admin right. Please Elevate and try again." } }
利用するときはこのようにします。 (例 : 2048 MBにするとき)
Set-PowerShellMemoryTuning -memory 2048