5

状況は、XML ドキュメントを文字列として返すリモート サーバーに対して WCF 呼び出しを行っていることです。

ほとんどの場合、この戻り値は数 K、時には数十 K、まれに数百 K ですが、ごくまれに数メガバイトになることもあります (最初の問題は、私が知る方法がないことです)。

悲しみを引き起こしているのは、これらのまれな機会です。次のようなスタック トレースが表示されます。

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at System.Xml.BufferBuilder.AddBuffer()
   at System.Xml.BufferBuilder.AppendHelper(Char* pSource, Int32 count)
   at System.Xml.BufferBuilder.Append(Char[] value, Int32 start, Int32 count)
   at System.Xml.XmlTextReaderImpl.ParseText()
   at System.Xml.XmlTextReaderImpl.ParseElementContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlTextReader.Read()
   at System.Xml.XmlReader.ReadElementString()
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMDRQuery.Read2_getMarketDataResponse()
   at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer2.Deserialize(XmlSerializationReader reader)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)

私は読んだことがありますが、それはラージオブジェクトヒープが断片化しすぎているためです。そのため、StringBuilder.EnsureCapacity へのクイックチェックを呼び出しの前に行っても、OutOfMemoryException がより早くスローされます (必要なものを推測しているため)。 、実際にはそれほど必要ないかもしれないので、私のチェックは解決するよりも多くの問題を引き起こしています)。私にできることはあまりないという意見もあります。

私が自分自身に尋ねた質問のいくつか:

  • メモリの使用量を減らします - リークをチェックしましたか? はい。メモリ使用量は増減しますが、これを保証する基本的な増加はありません。失敗することもありますが、以前はその段階で成功していました。
  • 少額の送金オプションではありません。これはサードパーティの Web サービスであり、私には制御できません (または、少なくとも解決には長い時間がかかります。それまでの間、まだ問題があります)。
  • LOH が失敗する可能性を低くするために、LOH に何かできることはありますか? ...今、これは最も実り多いコースです。これは 32 ビット プロセスですが (さまざまな政治的、技術的、および退屈な理由でそうする必要があります)、通常は数百メガバイトの空き領域があります (これまでに見られた失敗の最大量の倍数)。
  • LOH を監視できますか? perfmon を使用すると、ヒープのサイズを追跡できますが、使用可能な最大の連続したメモリ ブロックを監視する方法はないと思います。

質問: 試してみるべきことについて何かアドバイスや提案はありますか?

4

4 に答える 4

5

バインディングのTransferModeプロパティを確認して、既定値の "Buffered" から " Streamed " または " StreamedResponse " に変更する要件を満たしているかどうかを確認できます。

また、maxBufferPoolSizeおよびmaxBufferSizeの値を確認してください。使用される内部バッファーのサイズを大きくすると、特に大きなメッセージを処理する場合に、メモリの使用率が向上する可能性があります。

大きなメッセージを受信する場合は、 maxReceivedMessageSizeも既に設定されている可能性がありますが、その値も確認します。

上記の値の 1 つを見たことがあります。しきい値を超えた場合、不明瞭なメモリ関連のメッセージで失敗します。元の例外は、アプリケーションに表示されたメッセージによって実際には隠されていました。WCF トレースを有効にすると、問題を診断し、実際のエラーを確認するのに役立ちました。上記のバインド プロパティの 1 つまたは複数の値を増やす必要がありました。

あなたの投稿からあなたが使用しているバインディングの感触はわかりませんでしたが、これらの設定は主要なものに共通していると思います. たとえば、 basicHttpBindingに関するMSDN ドキュメントを確認してください。

それが本当に LOH フラグメンテーションである場合、チューニングの努力が尽くされた後は、何もする必要はありません。それを軽減するために、アプリケーションのローリング リサイクルが必要になる場合があります (私はそれをお勧めしません)。

于 2010-04-22T12:32:06.490 に答える
2

WCF 固有の問題に対処することはできませんが、32 ビット プロセスの LOH スペースを最大化する必要がある場合は、アプリケーションを大きなアドレスに対応させ、64 ビットで実行する必要があります。大規模なアドレス対応の 32 ビット プロセスは、64 ビット Windows で実行すると、4 GB のアドレス空間全体をアドレス指定できます。これにより、プロセスが通常使用するアドレス空間よりも大きなメモリのチャンクが得られます。

于 2010-12-05T10:34:18.357 に答える
1

あなたの問題は、このMSDNの記事に示されているように、 XmlSerializerを使用し、2つのコンストラクターのいずれかを使用していないことが原因であるアセンブリリークである可能性があると思います:

パフォーマンスを向上させるために、XML シリアル化インフラストラクチャはアセンブリを動的に生成して、指定された型をシリアル化および逆シリアル化します。インフラストラクチャは、これらのアセンブリを見つけて再利用します。この動作は、次のコンストラクターを使用する場合にのみ発生します。

XmlSerializer.XmlSerializer(タイプ)

XmlSerializer.XmlSerializer(型, 文字列)

他のコンストラクターのいずれかを使用すると、同じアセンブリの複数のバージョンが生成され、アンロードされないため、メモリ リークが発生し、パフォーマンスが低下します。

いいね。答えは、XmlSerializer をキャッシュすることです (作成したとしても)。

本当にそれを理解するには、Tessが指示したことを実行する必要があります。彼女はめちゃくちゃ天才です。

于 2010-06-03T13:49:50.390 に答える
1

可能であれば、ストリーム ベースのアプローチを採用し、フォワードのみの Xml パーサーを組み合わせて使用​​します。これにより、パフォーマンスも向上します。

WCF を絶対に使用する必要がない場合は、独自の HttpRequest を作成し、応答を XmlDeserializer に渡し、そのように応答を解析できます。問題が実際に発生する場所をより詳細に制御および洞察できる場合があります。探しているタイプの非常に大きなドキュメントを返すモック サービスを試すこともできます。私たちもLOHの断片化で頭を悩ませていたので、本当にあなたの痛みを感じています.

バッファを構築するときに気付いた問題 .NET は、バッファがいっぱいになるたびに容量が 2 倍になる傾向があり、サイズが 10 MB のドキュメントの場合、多くのステップでメモリを割り当てる必要があるため、メモリの断片化が発生します。必要なバッファサイズが事前にわかっている場合は、一度に割り当てる方が効率的です。したがって、受信ドキュメントの大きさがわかっている場合は、正確にそのサイズの StringBuilder を作成できます。

于 2010-12-05T10:28:03.633 に答える