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)、4 GB 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 回答