4

コードを実行しているときに、一見ランダムに見える「システムリソースを超えました」という例外が発生しています。私のプログラムの背後にある考え方は、サードパーティのソフトウェアがMicrosoft Accessデータベースファイル(.res)にデータを継続的に書き込んでいるということです-約30秒ごとに、私のコードはこのファイルからデータを読み取り、いくつかの操作を実行し、結果をデータベースに追加します。残念ながら、サードパーティのソフトウェアがファイルにデータを書き込む方法を変更することはできません。Accessデータファイルで立ち往生しています。

このエラーは、Click-Once発行でインストールされたWinFormsプログラムを実行している本番システムと、開発システムのコンソールテストプログラムの両方で発生します。単一の整数を返すクエリを実行し、他のプログラムやスレッドがローカルディスクにあるファイルにアクセスしていない場合でも、例外が発生します。

例外情報:

System.Data.OleDb.OleDbException (0x80004005): System resource exceeded.
   at System.Data.OleDb.OleDbCommand.ExecuteCommandTextErrorHandling(OleDbHResult hr)
   at System.Data.OleDb.OleDbCommand.ExecuteCommandTextForSingleResult(tagDBPARAMS dbParams, Object& executeResult)
   at System.Data.OleDb.OleDbCommand.ExecuteCommandText(Object& executeResult)
   at System.Data.OleDb.OleDbCommand.ExecuteCommand(CommandBehavior behavior, Object& executeResult)
   at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
   at System.Data.OleDb.OleDbCommand.ExecuteScalar()
...

問題を再現するサンプルコード:

string connectionString = @"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = C:\datafile.res";
string commandText = "SELECT MIN(Data_Point) FROM Channel_Normal_Table WHERE Test_ID = 1";

int connectionCounter = 0;            
object result;

while (true)
{                
    using (OleDbConnection connection = new OleDbConnection(connectionString))
    {
        connection.Open();
        connectionCounter++;

        using (OleDbCommand command = new OleDbCommand(commandText, connection))
        {
            result = command.ExecuteScalar();
        }

        connection.Close();
    }
}

残念ながら、例外は決定論的ではありません。同じファイルで同じコードを使用して、4番目のコマンド実行から6149番目までのどこかで発生するのを見てきました。これは常にcommand.ExecuteScalar()行で発生します。このコードにリソースリークがある場合は、それを見つけるのを手伝ってください。

http://support.microsoft.com/kb/2760394にある修正プログラムをインストールしようとしました(そして必要なレジストリを変更しました)が、問題は解決しません。どんな提案も歓迎され、積極的に追求されます。

これは、Windows 7、C#4.0(コンソールおよびWinForms)、4GBのRAMで実行されています

4

1 に答える 1

2

私があなたの場合に試みるいくつかのこと:

  1. データベースのユーザーはアプリケーションのみであるため、データベースを排他モードで開きます。これにより、ドライバーはロックファイルの管理のオーバーヘッドを取り除くことができます(データベースへのアクセスも高速化されます)。
// Share Mode=12 - exclusive mode (16 for multi-user)
string constr = @"Provider=Microsoft.ACE.OLEDB.12.0;" +
                 "Mode=12;Data Source = C:\datafile.res;user id=;password=;";
  1. プログラムの起動時にAccessデータベースへの接続を開き、アプリケーションが閉じるまで開いたままにします。
    タイトなループでは、ロックファイルの問題が発生し、デバッグが困難なあらゆる種類の奇妙な問題が発生します。
    Accessデータベースに単一のレコードを持つダミーテーブルを用意し、そのテーブルを開いてレコードを読み取りますが、その接続への永続的な参照を保持します。
private OleDbCommand PermanentCommand;

void KeepLinkOpen() {
   if (PermanentCommand == null || 
       PermanentCommand.Connection == null || 
       PermanentCommand.Connection.State == System.Data.ConnectionState.Closed) {

     OleDbConnection conn = new OleDbConnection(connectionString);
     conn.Open();
     PermanentCommand = new OleDbCommand("SELECT * FROM DummyTable", conn);
     PermanentCommand.ExecuteReader(System.Data.CommandBehavior.Default);
  }    
}

void Disconnect() {
  if (PermanentCommand != null) {
      if (PermanentCommand.Connection != null) {
          PermanentCommand.Connection.Close();
      }
      PermanentCommand.Dispose();
      PermanentCommand = null;
  }
}
于 2012-11-21T01:46:34.170 に答える