如何指示 PowerShell 对 .NET 对象(如 XmlSchemaSet)进行垃圾回收



我创建了一个PowerShell脚本,该脚本循环访问大量XML架构(.xsd)文件,并为每个文件创建一个.NET XmlSchemaSet对象,调用Add()Compile()向其添加架构,并打印出所有验证错误。

此脚本工作正常,但某处存在内存泄漏,导致它在 100 多个文件上运行时消耗千兆字节的内存。

我在循环中的基本操作如下:

$schemaSet = new-object -typename System.Xml.Schema.XmlSchemaSet
register-objectevent $schemaSet ValidationEventHandler -Action {
    ...write-host the event details...
}
$reader = [System.Xml.XmlReader]::Create($schemaFileName)
[void] $schemaSet.Add($null_for_dotnet_string, $reader)
$reader.Close()
$schemaSet.Compile()

(重现此问题的完整脚本可以在此要点中找到:https://gist.github.com/3002649。 只需运行它,然后观察任务管理器或进程资源管理器中的内存使用量增加。

受到一些博客文章的启发,我尝试添加

remove-variable reader, schemaSet

我还尝试从Add()那里拿起$schema并做

[void] $schemaSet.RemoveRecursive($schema)

这些似乎有一些效果,但仍然存在泄漏。 我假设较旧的XmlSchemaSet实例仍在使用内存而不会被垃圾回收。

问题:如何正确教导垃圾回收器它可以回收上述代码中使用的所有内存? 或者更一般地说:我怎样才能用有限的内存量来实现我的目标?

>Microsoft已经确认这是PowerShell 2.0中的一个错误,他们声明这已经在PowerShell 3.0中得到解决。

问题是使用 Register-ObjectEvent 注册的事件处理程序不会被垃圾回收。 在回应支持电话时,Microsoft说

"我们正在处理PowerShell v.2中的一个错误。问题是由 实际上,.NET 对象实例不再是 由于事件处理程序本身未释放而释放。这 问题不再可与PowerShell v.3重现"。

据我所知,最好的解决方案是在不同级别上在PowerShell和.NET之间进行交互:完全在C#代码(嵌入在PowerShell脚本中)中进行验证,然后只传回ValidationEventArgs对象的列表。 请参阅 https://gist.github.com/3697081 的固定复制脚本:该脚本功能正确且不泄漏内存。

(感谢Microsoft支持帮助我找到此解决方案。


最初Microsoft提供了另一种解决方法,即使用 $xyzzy = Register-ObjectEvent -SourceIdentifier XYZZY ,然后在最后执行以下操作:

Unregister-Event XYZZY
Remove-Job $xyzzy -Force

但是,此解决方法在功能上不正确。 在执行这两个附加语句时,任何仍在"进行中"的事件都将丢失。 就我而言,这意味着我错过了验证错误,因此脚本的输出不完整。

remove-variable后,您可以尝试强制收集 GC :

[GC]::Collect()

相关内容

  • 没有找到相关文章

最新更新