title: C# and Powershell Runspaces creating massive unmanaged memory leak
body: <p>I have a strange issue with a windows service that I'm developing in .Net 4. After an hour of running the service the memory usage is at 274MB. </p>
  
  <p>I have tried to find the cause of the leak by removing the functions one by one to find out where the leak occurs and at the moment because of this all the service does is run a PowerShell command <code>Get-WBSummary</code> every 10 seconds and capture the output to a string.</p>
  
  <p>I am trying to track down what is hogging all the memory using Red Gate .Net Profiler 10. When I look at the biggest hog of memory after an hour the only thing that sticks out is</p>
  
  <pre><code>Namespace         Class name         Live size (bytes)  Unmanaged size (bytes)
  System.Reflection RuntimeAssembly    1,400              1,462,189   
  </code></pre>
  
  <p>Which cant be right as that comes out to 1.462189mb.</p>
  
  <p>Here is the code I am using which runs every time the service timer hits 10 seconds (For testing I set it to a low value)</p>
  
  <pre><code>var Config = RunspaceConfiguration.Create();
  PSSnapInException Warning;
  
              if (Environment.OSVersion.Version.Major == 6 &amp;&amp; Environment.OSVersion.Version.Minor == 1)
              {
                  Config.AddPSSnapIn("Windows.ServerBackup", out Warning);
              }
  
              using (var Runspace = RunspaceFactory.CreateRunspace(Config))
              {
                  Runspace.Open();
                  PowerShell Ps;
                  using (Ps = PowerShell.Create())
                  {
                      Ps.Runspace = Runspace;
                      Ps.AddCommand("Get-WBSummary");
                      var Output = Ps.Invoke();
                      var Sb = new StringBuilder();
                      foreach (var PsObject in Output)
                      {
                          foreach (var PsPropertyInfo in PsObject.Properties)
                          {
                              Sb.AppendLine(PsPropertyInfo.Name + " " + PsPropertyInfo.Value);
                          }
                      }
                      PowershellOutput = Sb.ToString();
                  }
                  Runspace.Close();
                  Runspace.Dispose();
                  Ps.Dispose();
                  Config = null;
                  PowerShellSession.Stop();
                  PowerShellSession.Dispose();
                  GC.Collect();
  </code></pre>
  
  <p>Can anyone suggest what I might be doing wrong?</p>
  
  <p><strong>Edit</strong>:</p>
  
  <p>The problem here has nothing to do with the C# code but the way I was using PowerShell. The solution is instead of using one PowerShell runspace and entering the same command again and again in it (Which causes the PowerShell memory to increase to infinity) but to create a new PowerShell process every time and then close it when you are done</p>
  
  <pre><code>using (PowerShellProcessInstance ExternalPowerShellProccess = new PowerShellProcessInstance())
              {
                  ExternalPowerShellProccess.Process.Start();
                  var Config = RunspaceConfiguration.Create();
                  if (Environment.OSVersion.Version.Major == 6 &amp;&amp; Environment.OSVersion.Version.Minor == 1)
                  {
                      Config.AddPSSnapIn("Windows.ServerBackup", out PSSnapInException Warning);
                  }
                  Runspace Runspace = RunspaceFactory.CreateOutOfProcessRunspace(TypeTable.LoadDefaultTypeFiles(), ExternalPowerShellProccess);
                  Runspace.Open();
  
                  using (PowerShell Ps = PowerShell.Create())
                  {
                      Ps.Runspace = Runspace;
                      Ps.AddCommand("Get-WBSummary");
                      var Output = Ps.Invoke();
                      var Sb = new StringBuilder();
                      foreach (var PsObject in Output)
                      {
                          foreach (var PsPropertyInfo in PsObject.Properties)
                          {
                              Sb.AppendLine(PsPropertyInfo.Name + " " + PsPropertyInfo.Value);
                          }
                      }
  
                      PowershellOutput = Sb.ToString();
                      Ps.Dispose();
                      Runspace.Close();
                      Runspace.Dispose();
                  }
  </code></pre>