Memory leak using Powershell Remote Calls in C# Memory leak using Powershell Remote Calls in C# powershell powershell

Memory leak using Powershell Remote Calls in C#


I can see the problem in PS v3.0 but not in PS v2.0. Here is the code I use tosee this (all examples are in PowerShell):

for() {    $runspace = [runspacefactory]::CreateRunspace()    $runspace.Open()    $runspace.Close()    $p = Get-Process -Id $PID    '{0} {1}' -f $p.Handles, ($p.PrivateMemorySize / 1mb)}

It looks like handles and memory are leaking in v3.0 in the code above.

As far as v2.0 does not have this problem, one possible workaround may be tostart the service using PS v2.0, i.e. PowerShell.exe -Version 2.0.

If this is not possible I can think of two more workarounds. One of them is notto create runspaces directly but use [powershell] instead. For example, thiscode does not show the leak in v3.0:

for() {    $ps = [powershell]::Create()    $p = $ps.AddCommand('Get-Process').AddParameter('Id', $PID).Invoke()    '{0} {1}' -f $p.Handles, ($p.PrivateMemorySize / 1mb)    $ps.Dispose()}

Another workaround, if it is applicable, may be use of[runspacefactory]::CreateRunspacePool(). This way also does not show theleak:

$rs = [runspacefactory]::CreateRunspacePool()$rs.Open()for() {    $ps = [powershell]::Create()    $ps.RunspacePool = $rs    $p = $ps.AddCommand('Get-Process').AddParameter('Id', $PID).Invoke()    '{0} {1}' -f $p.Handles, ($p.PrivateMemorySize / 1mb)    $ps.Dispose()}#$rs.Close() # just a reminder, it's not called here due to the infinite loop

The last one also works much faster because the runspace is kind of reused.


I was also facing the same issue when I was using v1 of System.Management.Automation. But the issue was solved with v3 of System.Management.Automation and changing the code to use the CreateOutOfProcessRunspace method

Here is the code

            using (PowerShellProcessInstance instance = new PowerShellProcessInstance(new Version(4, 0), null, null, false))        {            using (var runspace = RunspaceFactory.CreateOutOfProcessRunspace(new TypeTable(new string[0]), instance))            {                runspace.Open();                using (PowerShell powerShellInstance = PowerShell.Create())                {                    powerShellInstance.Runspace = runspace;                    var filePath = GetScriptFullName(powerShellScriptType);                    powerShellInstance.Commands.AddScript(File.ReadAllText(filePath));                    var includeScript = GetIncludeScript();                    powerShellInstance.AddParameters(new List<string>                {                    userName,                    plainPassword,                    includeScript                });                    Collection<PSObject> psOutput = powerShellInstance.Invoke();                    // check the other output streams (for example, the error stream)                    if (powerShellInstance.Streams.Error.Count > 0)                    {                        // error records were written to the error stream.                        // do something with the items found.                        var exceptions = "";                        foreach (var error in powerShellInstance.Streams.Error)                        {                            exceptions += error.Exception + "\n";                        }                        throw new InvalidPowerShellStateException(exceptions);                    }                    return psOutput;                }            }        }