11

多数の XML スキーマ (.xsd) ファイルをループ処理する PowerShell スクリプトを作成し、それぞれに対して .NETXmlSchemaSetオブジェクトを作成し、 and を呼び出しAdd()Compile()スキーマを追加し、すべての検証エラーを出力します。

このスクリプトは正しく動作しますが、どこかにメモリ リークがあり、数百のファイルで実行すると数ギガバイトのメモリが消費されます。

私が基本的にループで行うことは次のとおりです。

$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 の Gistにあります。実行するだけで、タスク マネージャーまたはプロセス エクスプローラーでメモリ使用量の増加を確認できます。)

いくつかのブログ投稿に触発されて、追加してみました

remove-variable reader, schemaSet

$schema私もから拾ってAdd()やってみました

[void] $schemaSet.RemoveRecursive($schema)

これらはある程度の効果があるようですが、それでも漏れがあります。XmlSchemaSetの古いインスタンスは、ガベージ コレクションを行わずにメモリを使用していると推測しています。

質問:上記のコードで使用されたすべてのメモリを再利用できることをガベージ コレクターに正しく教えるにはどうすればよいでしょうか。または、より一般的には、限られた量のメモリで目標を達成するにはどうすればよいですか?

4

2 に答える 2

9

Microsoftは、これがPowerShell 2.0のバグであることを確認しており、PowerShell3.0で解決されたと述べています。

問題は、Register-ObjectEventを使用して登録されたイベントハンドラーがガベージコレクションされないことです。マイクロソフトは、サポートコールに応えて、次のように述べています。

「PowerShellv.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

ただし、この回避策は機能的に正しくありません。これらの2つの追加ステートメントが実行されるときに、まだ「実行中」のイベントはすべて失われます。私の場合、それは検証エラーを見逃していることを意味するため、スクリプトの出力は不完全です。

于 2012-07-16T15:38:33.537 に答える
4

その後、remove-variableGCコレクションを強制することができます:

[GC]::Collect()
于 2012-06-27T09:24:14.883 に答える