Hi all,
I have read many reports on different forums that people are finding Runspace objects created by RunspaceFactory.CreateRunspace cannot be cleanly disposed. These findings have been reported from as far back as 2009 and there seems to be no solution offered by Microsoft.
One post mentions that a Microsoft support call has been placed and the workaround/advise offered by Microsoft was to re-use the Runspace objects for as long as possible. So there seems to be indication that Microsoft was aware of this problem.
This memory leak is very easy to replicate:
for (int n = 0; n < 10; n++) { Runspace rs = null; try { Uri uri = new Uri(String.Format("https://{0}/ocspowershell", hostname)); SecureString passwordSecureString = new SecureString(); for (int i = 0; i < password.Length; i++) passwordSecureString.AppendChar(password[i]); PSCredential credential = new PSCredential(username, passwordSecureString); WSManConnectionInfo wsManInfo = new WSManConnectionInfo(uri, "http://schemas.microsoft.com/powershell/Microsoft.PowerShell", credential); wsManInfo.SkipRevocationCheck = true; rs = RunspaceFactory.CreateRunspace(wsManInfo); // <-- LEAK HERE } catch (Exception e) { Console.WriteLine("Exception: {0}", e.ToString()); } finally { rs.Dispose(); } }
I have tried to use UMDH and CLR Profiler to trace where the leak was coming from.
For every loop, you will find one of this allocation backtrace as captured by UMDH:
+ 420 ( 420 - 0) 10 allocs BackTrace1C5E0B20+ 10 ( 10 - 0) BackTrace1C5E0B20 allocations ntdll! ?? ::FNODOBFM::`string'+0001913B mscorwks!FieldMarshaler_StringUni::UpdateNativeImpl+00000033 mscorwks!FieldMarshaler::UpdateNative+00000072 mscorwks!LayoutUpdateNative+00000277 mscorwks!FmtClassUpdateNative+00000091 mscorwks!MarshalNative::StructureToPtr+0000019B System.Management.Automation.ni!???+00000000 : 7FEEF203D63 System.Management.Automation.ni!???+00000000 : 7FEEF207F5F System.Management.Automation.ni!???+00000000 : 7FEEF1F82EA System.Management.Automation.ni!???+00000000 : 7FEEF1FAA21 System.Management.Automation.ni!???+00000000 : 7FEEF1ED814 System.Management.Automation.ni!???+00000000 : 7FEEF1DFB1B System.Management.Automation.ni!???+00000000 : 7FEEF1CAB71 System.Management.Automation.ni!???+00000000 : 7FEEF1C8EA6 System.Management.Automation.ni!???+00000000 : 7FEEF1BAD3B System.Management.Automation.ni!???+00000000 : 7FEEF1DCC64 System.Management.Automation.ni!???+00000000 : 7FEEF28CEB6 System.Management.Automation.ni!???+00000000 : 7FEEF1DCD1E System.Management.Automation.ni!???+00000000 : 7FEEF1DC461<no module>!???+00000000 : 7FF001902E7
In the example above, UMDH captured 10 allocations of 42 bytes each.
This is a small leak and maybe that is why it could have gone unnoticed by many. In my case, I have a long running process and Runspace objects are re-used until they eventually got timed out. The Runspace objects end up in "Broken" state and cannot be re-opened anymore. I have no other options but to dispose these and create new ones.
After a long period of time, these 42-byte allocations begin to accumulate and become a real problem..
What is the solution?