2

私は最近、仕事用に保守しているアプリケーションでメモリ リークを発見しました。なぜコードがリークを引き起こすのか混乱しています。関連するコードを (わずかに変更して) 取り出し、以下に示します。

このアプリケーションでは、特定の XML ドキュメントを 1 つ以上の使用可能なスキーマ ファイルに対して検証できます。各スキーマ ファイルは、時間の経過とともに変更された XML ドキュメントの異なるバージョンに対応しています。XML ドキュメントが少なくとも 1 つのスキーマに対して検証されることのみを考慮します。各スキーマは、XML ドキュメントの内容を完全に記述します (ネストされたスキーマ ファイルではありません)。

ANTS メモリ プロファイラによると、スキーマ セットがクリアされた後でも、XmlDocument オブジェクトが以前のスキーマへの参照を保持しているようです。Validate() の呼び出しをコメントアウトし、他のすべてを同じままにすると、リークが停止します。

アプリケーションの初期化時に一度スキーマをロードし、妥当性が確認できるスキーマ ファイルが見つかるまで、XML ドキュメントに関連付けられているスキーマ ファイルを交換することで、アプリケーションのリークを修正しました。

以下のコードではメモリ リークが発生しますが、その理由はわかりません。

class Program
{
    private static XmlDocument xmlDocument_ = new XmlDocument();

    static void Main(string[] args)
    {
        using (StreamReader reader = new StreamReader("contents.xml"))
        {
            xmlDocument_.LoadXml(reader.ReadToEnd());
        }

        XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
        xmlReaderSettings.CloseInput = true;

        while (true)
        {
            xmlDocument_.Schemas = new XmlSchemaSet();

            XmlReader xmlReader = XmlReader.Create("schema.xsd", xmlReaderSettings);

            xmlDocument_.Schemas.Add(XmlSchema.Read(xmlReader, null));

            xmlReader.Close();

            xmlDocument_.Validate(null);
        }
    }
}
4

2 に答える 2

0

while以下のようにステートメントを変更してみてください。私はこれをテストしていませんが、元のコードとは異なり、すべてwhileの反復でXmlReader.

GC はXmlReader最終的にインスタンスを自動的に破棄する可能性がありますが、私はそれを疑っていXmlReaderますIDispose。つまり、使用するコードはXmlReader決定論的に破棄する必要があります (ガベージ コレクションは非決定論的です)。GC がそれらを破棄することができ、whileGC がこれを行う前に何千回も反復する場合、使用されるメモリはいずれにせよシステムを強制終了します。

while (true)
{
    xmlDocument_.Schemas = new XmlSchemaSet();

    using (XmlReader xmlReader = XmlReader.Create("schema.xsd", xmlReaderSettings))
    {
        xmlDocument_.Schemas.Add(XmlSchema.Read(xmlReader, null));
    }

    xmlDocument_.Validate(null);
}

編集:

のMSDN ページXmlDocument.Validateを読みました。このページには、検証オプションのXmlReaderSettings設定に使用して、これを別の方法で行うコード サンプルが記載されています。また、OP のコードは、XML ファイルが常に UTF-8 としてエンコードされていることを前提としています。テキスト エンコーディングを検出し、MSDN サンプルに基づいて書き直したものを次に示します。これにより、メモリリーク修正される場合があります。このコードはテストされていません。

class Program
{
    private static XmlDocument xmlDocument_ = new XmlDocument();

    static void Main(string[] args)
    {
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        settings.CloseInput = true;

        xmlDocument_.Load(XmlReader.Create("contents.xml", settings));

        while (true)
        {
            settings.Schemas = new XmlSchemaSet();
            settings.Schemas.Add(null, "schema.xsd");

            xmlDocument_.Validate(null);
        }
    }
}

ILDASM を試して、中身を確認できますXmlDocument.Validate

于 2013-03-07T00:04:50.333 に答える
0

XmlDocument 参照が静的であり、XML を検証するときに設定されるSchemaInfoプロパティが原因で、メモリ リークが発生します。これらのプロパティは、コンパイルされた XSD からのオブジェクトへの参照を保持するため、XmlDocument が存在する限り、(静的であるため) かなりの時間がかかる可能性があります。

一部の人々は、これが実際にリークであるかどうかについて議論するかもしれません: 別の XML を別の XSD セットで検証すると、以前に保持されていたリソースが解放されます。

于 2013-03-08T03:33:30.923 に答える