【问题标题】:How to instruct PowerShell to garbage collect .NET objects like XmlSchemaSet?如何指示 PowerShell 对 XmlSchemaSet 等 .NET 对象进行垃圾收集?
【发布时间】:2012-06-28 16:38:29
【问题描述】:

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

这个脚本可以正常工作,但是某处存在内存泄漏,如果在 100 个文件上运行,它会消耗 GB 的内存。

我基本上在一个循环中做的事情如下:

$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()

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

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

remove-variable reader, schemaSet

我也尝试从Add() 拿起$schema 并做

[void] $schemaSet.RemoveRecursive($schema)

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

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

【问题讨论】:

    标签: powershell memory-leaks garbage-collection xsd xmlschemaset


    【解决方案1】:

    Microsoft 已确认这是 PowerShell 2.0 中的错误,并表示已在 PowerShell 3.0 中解决此问题。

    问题是使用 Register-ObjectEvent 注册的事件处理程序没有被垃圾收集。在回复支持电话时,微软表示

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

    据我所知,最好的解决方案是在不同级别的 PowerShell 和 .NET 之间进行接口:完全在 C# 代码中进行验证(嵌入在 PowerShell 脚本中),然后返回一个 @ 列表987654322@ 对象。请参阅https://gist.github.com/3697081 处的修复复制脚本:该脚本在功能上是正确的并且不会泄漏任何内存。

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


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

    Unregister-Event XYZZY
    Remove-Job $xyzzy -Force
    

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

    【讨论】:

      【解决方案2】:

      remove-variable之后可以尝试强制GC回收:

      [GC]::Collect()
      

      【讨论】:

      • 这确实减少了增加,所以这在实践中可能会有所帮助;但使用的内存量仍在逐渐增加。
      • another StackOverflow answer 中所述,这在 PowerShell 中无法直接实现,也没有必要,因为根据推荐的 Microsoft 约定,Close() 暗示 Dispose()
      • @MarnixKlooster 我使用 powershell.exe.config 加载 .net 4.0 框架,我可以执行 $reader.dispose()。抱歉信息不正确。
      • 没问题——您能否简单描述一下您是如何“使用 powershell.exe.config 加载 .NET 4.0 框架”来回答这个问题的:stackoverflow.com/q/745956/223837?谢谢!
      猜你喜欢
      • 1970-01-01
      • 2011-07-16
      • 2012-03-26
      • 1970-01-01
      • 2019-09-04
      • 2010-11-08
      • 2012-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多