本文介绍了如何指示PowerShell垃圾收集像XmlSchemaSet这样的.NET对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个PowerShell脚本,它循环使用大量XML Schema(.xsd)文件,并为每个文件创建一个.NET object,calls 和向其添加架构,并打印出所有验证错误。 p>

这个脚本可以正常工作,但是在某处存在内存泄漏,导致它在数百个文件上运行时会消耗千兆字节的内存。



我在循环中基本做的是:

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

(重现此问题的完整脚本可以在此要点中找到:。只需运行它,并观察任务管理器或Process Explorer中的内存使用增加。)



受一些博客帖子的启发,我尝试添加

  remove-variable reader,schemaSet 

我还尝试从 Add()中执行 $ schema ,并执行

  [void] $ schemaSet.RemoveRecursive($ schema)

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



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

Microsoft已确认这是一个bug在PowerShell 2.0中,他们声明这已在PowerShell 3.0中得到解决。



问题是使用Register-ObjectEvent注册的事件处理程序不是垃圾收集。在回应支持电话时,微软表示,我们正在处理PowerShell v.2中的一个错误。这个问题是由于
实际上是由于事件处理程序本身不会被释放,所以.NET对象实例不再是

问题不再可以通过PowerShell v.3重现。


就我所见,最好的解决方案是在不同级别的PowerShell和.NET之间进行接口:完全验证在C#代码中(嵌入在PowerShell脚本中),并返回 ValidationEventArgs 对象的列表。请参阅上的固定复制脚本:该脚本在功能上是正确的并且不泄漏内存。



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






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

  Unregister-Event XYZZY 
Remove-Job $ xyzzy -Force

然而,此解决方法在功能上不正确。在执行这两条附加声明时,仍然处于正在运行的任何事件都将丢失。在我的情况下,这意味着我错过验证错误,所以我的脚本的输出是不完整的。


I created a PowerShell script which loops over a large number of XML Schema (.xsd) files, and for each creates a .NET XmlSchemaSet object, calls Add() and Compile() to add a schema to it, and prints out all validation errors.

This script works correctly, but there is a memory leak somewhere, causing it to consume gigabytes of memory if run on 100s of files.

What I essentially do in a loop is the following:

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

(A full script to reproduce this problem can be found in this gist: https://gist.github.com/3002649. Just run it, and watch the memory usage increase in Task Manager or Process Explorer.)

Inspired by some blog posts, I tried adding

remove-variable reader, schemaSet

I also tried picking up the $schema from Add() and doing

[void] $schemaSet.RemoveRecursive($schema)

These seem to have some effect, but still there is a leak. I'm presuming that older instances of XmlSchemaSet are still using memory without being garbage collected.

The question: How do I properly teach the garbage collector that it can reclaim all memory used in the code above? Or more generally: how can I achieve my goal with a bounded amount of memory?

解决方案

Microsoft has confirmed that this is a bug in PowerShell 2.0, and they state that this has been resolved in PowerShell 3.0.

The problem is that an event handler registered using Register-ObjectEvent is not garbage collected. In reponse to a support call, Microsoft said that

The best solution, as far as I can see, is to interface between PowerShell and .NET at a different level: do the validation completely in C# code (embedded in the PowerShell script), and just pass back a list of ValidationEventArgs objects. See the fixed reproduction script at https://gist.github.com/3697081: that script is functionally correct and leaks no memory.

(Thanks to Microsoft Support for helping me find this solution.)


Initially Microsoft offered another workaround, which is to use $xyzzy = Register-ObjectEvent -SourceIdentifier XYZZY, and then at the end do the following:

Unregister-Event XYZZY
Remove-Job $xyzzy -Force

However, this workaround is functionally incorrect. Any events that are still 'in flight' are lost at the time these two additional statements are executed. In my case, that means that I miss validation errors, so the output of my script is incomplete.

这篇关于如何指示PowerShell垃圾收集像XmlSchemaSet这样的.NET对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 12:52