Cmdlet实例持续多久?
对派生的 Cmdlet 的自定义实现会是什么样子感兴趣,真的想看看涉及多少工作。模拟了以下内容:
using System.Management.Automation;
namespace EMSEngineering
{
[Cmdlet(VerbsDiagnostic.Test, "Cmdlet")]
public class TestCmdlet : Cmdlet
{
static int nextIndex = 0;
private int index = nextIndex;
public TestCmdlet()
{
System.Console.WriteLine("instantiating {0}", index);
nextIndex++;
}
~ TestCmdlet()
{
System.Console.WriteLine("terminating {0}", index);
}
[Parameter(Mandatory = true, ValueFromPipeline = true)]
public string[] SomeParameter { get; set; }
protected override void BeginProcessing()
{
if (SomeParameter != null)
WriteVerbose(string.Format("begin processing {0} params", SomeParameter.Length));
}
protected override void ProcessRecord()
{
foreach (string param in SomeParameter)
WriteObject(string.Format("processing {0}", param));
}
protected override void EndProcessing()
{
if (SomeParameter != null)
WriteVerbose(string.Format("end processing {0} params", SomeParameter.Length));
}
protected override void StopProcessing()
{
WriteVerbose("stop processing");
}
}
}
这里没什么特别的,但是在提示下调用时,我注意到了一些意想不到的事情。
PS E:usersbitbucketcrmcallBuild_PI> '1','2' | Test-Cmdlet
实例化 0
处理 1
处理 2
PS E:usersbitbucketcrmcallBuild_PI> '1','2' | Test-Cmdlet
实例化 1
处理 1
处理 2
PS E:usersbitbucketcrmcallBuild_PI> 退出
终止 1
终止 0
每次调用我的模拟 Cmdlet 都会启动一个新实例。他们只在我退出 shell 时才终止。我在一个更大的循环中尝试了这个,这个循环重复了 10 次或更多次。相同的结果 - 每次调用都有新实例,并且都在 shell 退出时终止。
所有 Cmdlet 都是这种情况吗?它们真的只是堆叠起来直到 shell 退出吗?我在实现中遗漏了什么吗?
回答
-
实际上,对 cmdlet 的每次调用都会创建实现 .NET 类的新实例。
-
这些实例最终会被垃圾收集(时间不确定,收集可能需要几分钟的时间),但您可以通过显式调用.NET 垃圾收集器来强制同步处理:
[GC]::Collect(); [GC]::WaitForPendingFinalizers()
笔记:
-
默认情况下,垃圾收集器会定期运行,并且如上所述,可能需要几分钟才能真正释放给定对象;然而,垃圾收集器也在低内存情况下按需运行,甚至周期性运行的频率也取决于内存条件(另一种说法:没有固定频率) - 请参阅垃圾收集基础帮助主题了解更多信息。
- 举一个频率可变性的例子:在进入PowerShell 会话后不久,内存压力明显更高,使得近乎即时的垃圾收集更有可能。
-
在某些情况下,cmdlet 实现实例的垃圾收集会立即发生:
-
如果您通过
-?:调用帮助Test-Cmdlet -?(虽然不是通过Get-Help Test-Cmdlet,这不需要实例化 cmdlet 类)。 -
如果调用在语法上无效,例如尝试使用未知参数时;例如:
Test-Cmdlet -NosuchParam -
其他的?
-