3

マルチスレッド Web サーバーとして機能する C# プログラムがあります。Sql Server データベースに保持されている Xml 構造の多くの処理を行います。

これらの Xml 構造のサイズが大きくなると、アプリのメモリが不足していることがわかります。

私は ANTS メモリ プロファイラーを展開して何が起こっているかを確認し、処理中にメモリに保持される大きな文字列の数を減らすことに成功し、状況を少し改善しました。

ただし、接続プールに保持されている大きなバイト配列が原因で、フラグメント化された大きなオブジェクト ヒープが残っています。大きなバイト配列は

TdsParserStateObject._bTmp
in TdsParser._physicalStateObj
in SqlInternalConnectionIds._parser
in DbConnectionInternal[0]
in DbConnectionPool._objectList

スレッドの実行中はスレッドごとに 1 つの接続を開いたままにしていますが、using ステートメント内でのみ接続を使用していると 99.9% 確信しています (これは最適化を目的としていますが、事態を悪化させているかどうかは疑わしいです)。

接続が保持するメモリの量を減らすために接続に対してできることはありますか (接続を閉じるか破棄する以外に)。

または、使用するたびにすべての接続をすぐに閉じるか破棄する必要がありますか?

[後で-私のコメントに従って]データベースアクセスごとに新しい接続を使用するようにコードをリファクタリングし、後で破棄します(もちろん、トランザクションの最初から最後まで同じ接続を使用するトランザクションを除き、取引で処分します。)

プログラムがアイドル状態 (つまり、接続が使用されていない状態) であっても、接続プールには大量のメモリを占有する接続が存在し、断片化を引き起こします。

破棄された接続が接続プールに 58MB のメモリを保持するのはなぜですか?

[さらに後で] Sql Server 接続プールが大きなヒープを断片化するのを防ぐ解決策があります。これは、おそらく巨大なバッファーを持つ接続を検出し、破棄時にプールから削除するようにマークすることです。

SqlConnection.ClearPool(接続)

私は現在、DataReader をサブクラス化し、返されたフィールドのサイズが 10MB を超えているかどうかを検出するという、かなりハックな方法でこれを行っています。

どの接続に大きなバッファがあるかを検出するより良い方法についての提案を歓迎します。

トランザクション内でどの接続を使用するかを追跡する (明らかにトランザクションである必要があります) ため、すべてのデータベース アクセスで接続を開いて破棄するように変更を元に戻したことに注意してください。

スレッドの開始時に開かれ、最後に閉じられた接続は問題ありません。ほぼすべてのスレッドが存続期間が短い (単一の Web 要求への応答であるため) ためです。例外は、とにかく単一のトランザクションのコンテキストでおそらく動作するバッチ プロセスです。

4

2 に答える 2

3

ADO.NET を使用している場合、接続を開いたままにしておく必要はありません。接続はデフォルトでプールされ (自分でプールをオフにしない限り)、ADO.NET がプールのすべての管理を行います。接続パラメーターが同一である場合にのみ接続がプールされるため、異なるユーザー資格情報などについて心配する必要さえありません。メモリ使用量の観点から、接続の破棄は役に立ちます。

これについての詳細:

于 2013-11-10T00:35:58.010 に答える
2

Szymonの答えはある程度までは良いので、投票しました。

しかし、彼の答えでは解決できない問題がいくつかあります。非常に大きなデータ (私の場合、約 10 MB の Xml を含む単一のテキスト フィールド) が SqlConnection を介して取得されると、接続の内部バッファーが非常に大きくなるように見えます。

同時に多くの接続を使用するプログラムがあり、大規模なデータを扱う場合、関係する SqlConnection を Disposed した後も、これらの大きなバッファが接続プールによって参照されたままになり、大規模なデータ ヒープの断片化につながります。

これを防ぐために私が見つけた唯一の方法は、大きなデータに使用された SqlConnections を検出し、それらを破棄する前に接続プールから削除することです。

私の質問の後の編集でわかるように、DataReader をサブクラス化し、返されたフィールドのいずれかが終了しているかどうかを検出することによって、SqlConnection 内部バッファーが大きいかどうかを検出する洗練された方法を見つけられませんでした。サイズは10MB!

于 2013-11-18T18:00:47.677 に答える