2016-06-24 4 views
2

Я использую объект IBM.Data.DB2.DB2DataAdapter, чтобы сделать несколько подключений к различным базам данных на разных серверах.
Моей основной контур и подключение структура выглядит следующим образом:DB2Connection Object Looping Открыть, затем закрыть исключения памяти

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 или около того база данных на разных серверах, я в конечном итоге в конечном итоге получаю это исключение. Я не могу контролировать распределение памяти для каждого экземпляра db.

ОШИБКА [57019] [IBM] SQL1084C Менеджеру базы данных не удалось выделить общую память, так как достигнут предельный уровень памяти ядра операционной системы. SQLSTATE = 57019

Единственный способ, которым я был в состоянии обойти это поставить сон нить перед каждым дб вызова, такие как:

System.Threading.Thread.Sleep(3000); 

Я ненавижу это, любые предложения будут оценены.

+0

Код не дает четкого изображения (не указан код 'sqlCommand' передан и как/где' _connection' не отображается). Но сообщение об ошибке не подразумевает «DBConnection». Объекты DBProvider должны быть удалены, и они не выглядят так, как вы. – Plutonix

+0

Я обновил код, чтобы лучше показать, как я использую объекты db2. – Airborne

ответ

3

В коде публикуемой, то Connection, Command и DataAdapter все IDisposable указания, что они должны быть утилизированы, чтобы освободить выделенные ресурсы. Но фактически только объект DBConnection. В частности, в такой петле, какой у вас есть, важно избавиться от них, чтобы предотвратить утечки.

У меня нет поставщиков DB2, но все они работают практически одинаково, особенно в этом отношении. Я бы начал с рефакторинга кода, начиная с MyDBObject. Вместо того, чтобы просто держась строки соединения Params, которые он создает соединение (ы) для Вас:

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, чтобы заполнить таблицу. Опуская это означает, что создано менее одного IDisposable.
  • Вместо того, чтобы передавать команду, перейдите в SQL. Это позволяет также создавать, использовать и утилизировать объект DBCommand.
  • Если есть вероятность того, что 2 таблицы в одном и том же БД будут опрошены, я бы реорганизовал дальше, чтобы можно было заполнить обе таблицы в одном и том же соединении.

До: 2 из 3 объектов не были расположены (! на итерацию)
После: 2 из 2 объектов расположены.

Я подозреваю, что виновником был объект DBCommand (по аналогии с this question), но это может быть их комбинация.

Включение нити в сон (возможно) работает, потому что дает GC возможность догнать очистку. Вы, вероятно, еще не из леса.В приведенной выше ссылке возникали проблемы с 400 итерациями; 20 или даже 40 (20 * 2 объекта) кажутся очень маленьким числом для исчерпания ресурсов.

Итак, я подозреваю, что другие части кода также не могут правильно утилизироваться, и этот цикл представляет собой только соломинку, которая ломает спину верблюда. Ищите другие циклы и объекты БД, которые используются и не забудьте их уничтожить. В принципе, все, что имеет метод Dispose(), должно использоваться в блоке using.

+0

Я собираюсь изменить свой код и проверить ваши предложения когда-нибудь сегодня. Спасибо, спасибо. – Airborne

+0

Я обернул любые объекты db в использовании операторов и с моими 20 + различными подключениями к db и запросами, которые он отлично работает до сих пор, без какого-либо спящего потока. Благодаря! – Airborne

+0

Приятно слышать. Имейте в виду, что код в вопросе действительно просто выявил проблему. Я думаю, что приложение может позволить себе опираться на те 20-40 объектов, поэтому код в другом месте, вероятно, также протекает. Настоящим ключом является последнее предложение в ответе: * «все, что имеет метод' Dispose() ', должно использоваться в блоке использования» * – Plutonix

 Смежные вопросы

  • Нет связанных вопросов^_^