Mar*_*ica 11 powershell xsd garbage-collection memory-leaks xmlschemaset
我创建了一个PowerShell脚本,它循环遍历大量的XML Schema(.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()
Run Code Online (Sandbox Code Playgroud)
(可以在此要点中找到重现此问题的完整脚本:https://gist.github.com/3002649.只需运行它,并在任务管理器或Process Explorer中观察内存使用量的增加.)
受到一些博客帖子的启发,我尝试添加
remove-variable reader, schemaSet
Run Code Online (Sandbox Code Playgroud)
我也尝试过$schema从中Add()做起
[void] $schemaSet.RemoveRecursive($schema)
Run Code Online (Sandbox Code Playgroud)
这似乎有一些影响,但仍有泄漏.我假设旧的实例XmlSchemaSet仍在使用内存而不进行垃圾回收.
问题:我如何正确地教垃圾收集器它可以回收上面代码中使用的所有内存?或者更一般地说:如何通过有限的内存来实现我的目标?
Microsoft已经确认这是PowerShell 2.0中的一个错误,他们声明这已在PowerShell 3.0中得到解决.
问题是使用Register-ObjectEvent注册的事件处理程序不是垃圾回收.在回应支持电话时,微软表示
"我们正在处理PowerShell v.2中的一个错误.问题实际上是由于事件处理程序没有自行释放而导致.NET对象实例不再发布的事实.使用PowerShell不再可以重现这个问题第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
Run Code Online (Sandbox Code Playgroud)
但是,此解决方法在功能上是不正确的.在执行这两个附加语句时,任何仍在"飞行中"的事件都将丢失.就我而言,这意味着我错过了验证错误,因此我的脚本输出不完整.
| 归档时间: |
|
| 查看次数: |
15896 次 |
| 最近记录: |