DB2Connection 对象循环打开然后关闭内存异常

DB2Connection Object Looping Open then Close Memory Exceptions

我正在使用 IBM.Data.DB2.DB2DataAdapter 对象与不同服务器上的不同数据库建立多个连接。
我的基本循环和连接结构如下所示:

foreach (MyDBObject db in allDBs)
{
    //Database Call here for current DB...//Get SQL, then pass it to DB call
    QueryCurrentDB(command);
}

然后...

DB2Connection _connection;    

Public DataTable QueryCurrentDB(DB2Command command)
{

    _connection = new DB2Connection();
    DB2DataAdapter adapter = new DB2DataAdapter();

    _connection.ConnectionString = string.Format("Server={0};Database={1};UID={2};PWD={3};", _currentDB.DBServer, _currentDB.DBName, _currentDB.UserCode, _currentDB.Password);
    command.CommandTimeout = 20;
    command.Connection = _connection;
    adapter.SelectCommand = command;                
    _connection.Open();

    adapter.Fill(dataTable);

    _connection.Close();
    _connection.Dispose();

    return dataTable;
}

如果我在不同的服务器上有大约 20 个左右的数据库,我最终会得到这个异常。我也无法控制每个数据库实例的内存分配。

错误 [57019] [IBM] SQL1084C 数据库管理器无法分配共享内存,因为已达到操作系统内核内存限制。 SQLSTATE=57019

我能够解决这个问题的唯一方法是在每次调用数据库之前让线程休眠,例如:

System.Threading.Thread.Sleep(3000);

我讨厌这个,如有任何建议,我们将不胜感激。

在发布的代码中,ConnectionCommandDataAdapter 都是 IDisposable,表示需要释放它们以释放分配的资源。但实际上只有 DBConnection 对象被释放。特别是在像您这样的循环中,处理这些以防止泄漏很重要。

我没有 DB2 提供程序,但它们的工作原理几乎相同,尤其是在这方面。我将从重构以 MyDBObject 开始的代码开始。让它为您创建连接,而不是仅仅保留连接字符串参数:

class MyDBObject 
{ 
    private const string fmt = "Server={0};Database={1};UID={2};PWD={3};";
    ...
    public DB2Connection GetConnection()
    {
        return new DB2Connection(string.Format(fmt,
                    DBServer,DBName,UserCode,Password));
    }
}

然后循环方法:

// this also could be a method in MyDbObject
public DataTable QueryCurrentDB(string SQL)
{
    DataTable dt = new DataTable();
    using (DB2Connection dbcon = currentDB.GetConnection())
    using (DB2Command cmd = new DB2Command(SQL, dbcon))
    {
        cmd.CommandTimeout = 20;
        dbcon.Open();
        dt.Load(cmd.ExecuteReader());
    }
    return dt;
}
  • 最重要的是,请注意 IDisposable 对象都包含在 using 块中。这将处置(并关闭)目标并释放分配的所有资源。
  • 您不需要 DataAdapter 来填充 table。省略它意味着少了一个 IDisposable 创建的东西。
  • 不是传递命令,而是传递 SQL。这还允许您创建、使用和处置 DBCommand 对象。
  • 如果同一个数据库中的 2 个 table 有机会被轮询,我会进一步重构,以便可以在同一个连接上填充两个 table。

之前:3 个对象中有 2 个未被处理(每次迭代!
之后:处理了 2 个对象中的 2 个。

我怀疑罪魁祸首是 DBCommand 对象(类似于 ),但也可能是它们的组合。

让线程休眠(可能)有效,因为它让 GC 有机会赶上清理工作。你可能还没有走出困境。上面的 link 在 400 次迭代时变成了 运行 问题; 20 甚至 40(20*2 个对象)似乎是一个耗尽资源的非常小的数字。

因此,我怀疑代码的其他部分也未能正确处理,而该循环只是压垮骆驼的最后一根稻草。查找正在使用的其他循环和 DB 对象,并确保处置它们。基本上,任何具有 Dispose() 方法的东西都应该在 using 块中使用。