如何指示 PowerShell 对 XmlSchemaSet 等 .NET 对象进行垃圾收集? [英] How to instruct PowerShell to garbage collect .NET objects like XmlSchemaSet?

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

问题描述

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

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.

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

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

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

(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

我也尝试从 Add() 中获取 $schema 并做

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

[void] $schemaSet.RemoveRecursive($schema)

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

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 已确认这是 PowerShell 2.0 中的错误,并表示已在 PowerShell 3.0 中解决此问题.

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

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

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

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

"we’re dealing with a bug in PowerShell v.2. The issue is caused actually by the fact that the .NET object instances are no longer released due to the event handlers not being released themselves. The issue is no longer reproducible with PowerShell v.3".

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

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.

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

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

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

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 对象进行垃圾收集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆