8

これは本当にクレイジーなバグです。以下は、OutOfMemoryException非常に短く単純な XML スニピットに対して , をスローしています (例<ABC def='123'/>: ):

public static T DeserializeXmlNode<T>(XmlNode node)
{
    try
    {
        return (T)new XmlSerializer(typeof(T))
            .Deserialize(new XmlNodeReader(node));
    }
    catch (Exception ex)
    {
        throw; // just for catching a breakpoint.
    }
}

この MSDN の記事で、コンストラクターで追加のパラメーターを指定して XmlSerializer を使用していた場合、呼び出されるたびにキャッシュされていないシリアライザー アセンブリが生成され、Assembly Leakが発生することを読みました。しかし、コンストラクターで追加のパラメーターを使用していません。また、新しく開始された AppDomain で初めて呼び出されたときにも発生するため、意味がありません。

何を与える?

4

4 に答える 4

4

私の質問に対する最終的な答えは、これに遭遇したすべての人に役立つわけではありませんが、私の同僚の何人かは、今月後に別の製品の別のシステムで遭遇しました. 数か月後、彼らがここで私の投稿を見つけたとき、彼らは笑って、ここで解決策が受け入れられなかったので、私が実際にそれを解決したかどうか疑問に思いました.

最終的な解決策は、デシリアライズの問題とは何の関係もありません。代わりに、すべてではないにしても多くのアプリケーションが使用しているプロバイダーである Oracle ODP.NETデータベース クライアントの新しいコピーを完全にアンインストールしてインストールする必要がありました。

事例証拠に基づくと、この問題は不適切にパッチが適用されたバージョンの ODP.NET アセンブリで発生し、その後仮想マシンのクローンを介して他のシステムに伝播されたようです。

ODP.NET を完全に削除し、互換性のある新しいバージョンを Oracle の Web サイトから取得してインストールすると、問題は完全に解消されました。

仮説は、使用可能な (ただし破損している) ODP.NET ドライバーに安全でないコードが含まれておりDeserialize、最初の使用後にメソッドの近くにある .NET 保護メモリ領域を繰り返し上書きしていたというものです。ODP.NET 呼び出しの前に呼び出された場合Deserialize、問題なく動作します。ただし、ODP.NET 呼び出しを使用した後の Deserialize への後続の呼び出しはすべて、惨めに失敗します。

これに対する最終的な解決策は、2 つの異なる製品で 2回解決されており、ODP.NET の適切な/新しい/クリーンな/新しいコピーをインストールすることです。

きれいではありません...しかし、それはそれを解決したものです。

于 2011-02-16T22:11:19.233 に答える
2

編集:残念ながらこれは解決策ではありませんでしたが、他の人が非常によく似た問題を追跡するのに役立つかもしれません. ここでのこの答えは、実際の解決策です。

私はこの問題の解決策を見つけたと信じています。これは.NET 3.5 SP1のバグです。

3.5 SP1 で静的デリゲートと ISerializable を使用すると、シリアライゼーションがハングするか OutOfMemoryException がスローされます(ID: 361615 ):

ジェネリック クラスが ISerializable を実装し、ジェネリック型引数を使用する静的デリゲート メンバーを持つ場合、バイナリ デシリアライゼーションがハングする (Windows Server 2003 を使用する 32 ビット システムの場合) か、OutOfMemoryException をスローする (Windows Server を使用する 64 ビット システムの場合) 2008)。

このエラーは .NET 3.5 SP1 で発生し、SP1 なしの .NET 3.5 では発生しませんでした。

解決策は、 KB957543ホット フィックスをインストールすることです。

于 2010-05-17T18:59:15.187 に答える
1

XmlSerializer クラスのドキュメントに基づいて、XmlSerializer をキャッシュする必要があります。そうしないと、パフォーマンスの低下やメモリ リークが発生する可能性があります。

Hashtable serializers = new Hashtable();

// Use the constructor that takes a type and XmlRootAttribute.
XmlSerializer s = new XmlSerializer(typeof(MyClass), myRoot);

// Implement a method named GenerateKey that creates unique keys 
// for each instance of the XmlSerializer. The code should take 
// into account all parameters passed to the XmlSerializer 
// constructor.
object key = GenerateKey(typeof(MyClass), myRoot);

// Check the local cache for a matching serializer.
XmlSerializer ser = (XmlSerializer)serializers[key];
if (ser == null) 
{
    ser = new XmlSerializer(typeof(MyClass), myRoot);
    // Cache the serializer.
    serializers[key] = ser;
}
else
{
    // Use the serializer to serialize, or deserialize.
}
于 2010-05-13T13:41:10.277 に答える
1

問題を再現するのに十分な詳細が提供されていません。ただし、リーダーは IDisposable を実装しており、適切に破棄する必要があります。できれば using ブロックでラップします。ほとんどの開発者は、何かを処分するのを忘れたときに問題に遭遇することはありません。これは、ガベージ コレクターが最終的に混乱を解消するためです。ただし、GC がクリーンアップを開始する前に問題を引き起こしたり、クリーンアップを完全に妨げたりするコードを作成することは難しくありません。

public static T DeserializeXmlNode<T>(XmlNode node)
{
    XmlSerializer xs = new XmlSerializer(typeof(T));
    using(XmlNodeReader xr = new XmlNodeReader(node))
        return (T)xs.Deserialize(xr);
}
于 2010-05-12T22:47:49.160 に答える