3

サーバー上にある Oracle DB に対して実行される ac# 3.5 フレームワーク Windows アプリケーションがあります。

アプリケーションのフォームの 1 つには、上部に 8 つのタブがあります。各タブのタブ コンテンツ領域内にはコンボボックスがあります。コンボボックスには、各フォームに同じ情報が表示されます。ユーザーがドロップダウンまたはキーボードの矢印を使用してコンボボックスの値を変更すると、8 つのタブ付き領域に、Oracle から取得したデータが入力されます。

既存のプログラムの構造に基づいて、コンボボックスが変更されるたびに、約 20 の個々の DB 接続が開かれます。まず、さまざまなタブから正しいテーブルにデータを保存するために、約 8 つが呼び出されます。各タブの内容は、そのタブのデータを保存するために DB クラスに渡されます。次に、コンボボックスに基づいてテーブルからタブをロードするために、約 8 回の DB 呼び出しが行われます。

明確にするために、車のモデルを変更するタブでコンボボックスを選択するようなものです。各タブは、「インテリアオプション」「エンジンオプション」などのようなものになります。

次に、ID に基づいて高レベルのレコードをロックするために DB 呼び出しが 2 回行われ、他の誰もその特定のレコードを同時に編集できなくなります。

全体として、プロセスはかなり堅実です。セーブ/ロード時間は爆速です。ほぼ瞬時にデータを保存/読み込みして、2 つの異なるコンボボックスの値を切り替えることができます。

次に問題が発生します

十分な速さで前後にスピンすると (何人かのユーザーも同様に行っています)、プログラム全体がハングします。クラッシュすることはありません。ハングするだけです。

デバッグ環境でこれを繰り返すと、常に同じコード行で停止していることがわかりました (単純なレコードセットの割り当て (たとえば、CarModelInterior.Notes = Convert.ToString(myReader[6]);))。

その後、ガベージ コレクター (GC) スレッドがバックグラウンドで実行されていましたが、毎回同じ場所で停止していました。

RED-Gate メモリ/パフォーマンス モニターのインストールに入ります。

私が見つけたのは、コンボボックスの値を切り替える速度が速ければ速いほど、GC Finalizer キューがいっぱいになる速度が速かったことです。最終的に、同じ SQL 呼び出しがリストの一番上にあったようです。

私の仮定と当て推量を入力してください。

私の考えでは、開かれている接続が多すぎて十分な速度でファイナライズされていないか、どこかでロックが発生しています。

私が言えることは、プログラム全体のすべての DB 呼び出し (すべての異常な呼び出し) が "USING" ステートメントを使用しているため、すべての破棄が自動的に完了するということです。また、すべて(はい、アプリケーション全体をチェックしたように)、すべてのDB呼び出しはプライマリスレッドにあります。したがって、各コンボボックス値の変更に対して行われる 20 ほどの DB 呼び出しはすべて順番に行われます。これにより、少なくともシングルスレッドの問題である限り、ロックの可能性が排除されました。

私は何を残していますか?この時点で、私はあきらめてここに投稿したほどのグーグルです。ファイナライズ キューの処理速度が十分でない可能性はありますか? 他のアイデアはありますか?

4

1 に答える 1

1

リソースを再利用する前に、OracleCommand を Disposed する必要があります。 Command オブジェクトの基本クラスであることが多いDbCommandは、IDisposable を実装します。比較すると、System.Data.SqlClient.SqlCommand は破棄する必要がないように見えるため、多くの DbCommand 実装では破棄が必要であることを開発者が忘れる可能性があります。コマンドが破棄されない場合、ガベージ コレクタは最終的に Finalize メソッドを呼び出して、管理されていないリソースを解放します (Oracle クライアントの OracleCommand の実装が object.Finalize をオーバーライドすると仮定します)。

于 2011-06-07T18:02:12.140 に答える