Проблема с памятью в приложении Winforms - память увеличивается при каждом поиске и привязке - PullRequest
1 голос
/ 30 сентября 2010

У меня проблема с памятью в моем приложении. Каждый раз, когда я выбираю данные из базы данных и назначаю их Grid, объем памяти увеличивается, а иногда, когда выполняется расширенный поиск, объем памяти достигает 1 ГБ.

Могут быть и другие проблемы с обработкой памяти, но для проверки того, что поиск и привязка данных многократно потребляют хорошее количество памяти, я создал новое приложение winforms, опустил на него кнопку и сетку и написал этот код.

private void button1_Click(object sender, EventArgs e)
{
    using (SqlConnection con = new SqlConnection(connString))
    {
    SqlDataAdapter adp = new SqlDataAdapter("select * from supplier", con);
    DataSet ds = new DataSet();

    con.Open();
    adp.Fill(ds);
    con.Close();

    dataGridView1.DataSource = ds.Tables[0];                                
    ds.Dispose();
    }
}

Каждый раз, когда я нажимаю на эту кнопку, использование памяти этим приложением увеличивается, иногда на 3 МБ, иногда на 4 МБ и т. Д. В таблице содержится около 2000 записей и 12 столбцов различных типов, таких как datetime, VARCHAR(100), int и т. Д.

Освобождение памяти через несколько минут Если я перестану повторять операции поиска и привязки.

Почему память просто увеличивается каждый раз, если объем данных одинаков?

Я также попробовал следующий код, но без разницы.

dataGridView1.DataSource = null;
dataGridView1.DataSource = ds.Tables[0]; 

Я использую Telerik элементы управления в моем исходном приложении. Сетка Telerik потребляет больше памяти, чем DataGridView, но DataGridView работает так же.

Помните, этот пример состоит только из одной формы, кнопки и сетки в этой форме.

Спасибо.

Ответы [ 2 ]

2 голосов
/ 30 сентября 2010

ds.Dispose () ничего не будет делать, потому что данные все еще привязаны к сетке. В следующий раз, когда вы создадите новый ds, заполните его, а затем свяжете, старые значения ds больше не будут привязаны, но сборщик мусора не обязательно будет немедленно очищен. Каждый раз, когда вы нажимаете, вы потребляете больше памяти, не освобождая ее. Память со временем освобождается, потому что, когда вы прекращаете повторный поиск и привязку, GC получает возможность очистить старые несвязанные данные.

Несмотря на то, что приблизительный размер данных для каждого поиска должен быть одинаковым, для new'd ds и datagridview, каждый раз через это уникальное событие, и нет никакой корреляции с данными предыдущего поиска / связывания.

Я думаю, но определенно не уверен, что GC спроектирован так, чтобы не влиять на производительность, то есть он не должен занимать центральный процессор для сбора данных, если нет существенных проблем с памятью. Он должен попытаться сделать очистку во время простоя процессора. В этом случае все операции поиска и привязки фактически задерживают GC.

1 голос
/ 30 сентября 2010

DataSet - это тяжелый объект, который нужно использовать только для извлечения данных из базы данных.Это полезно только в том случае, если вам нужно иметь несколько таблиц со связями и т. Д. Думайте об этом как о базе данных в памяти, которая может синхронизироваться с вашей постоянной базой данных.

Один из вариантов - использовать пользовательский объект и DataReaderперебрать и заполнить List<yourObject>.Это, вероятно, потребляет наименьшее количество памяти.

Другой вариант, который приближает его к тому, что у вас есть, - это пропуск DataSet.Попробуйте что-то вроде этого и посмотрите, улучшится ли использование памяти:

using (SqlConnection myConnection = new SqlConnection(connectionString))
using (SqlCommand myCommand = new SqlCommand("select * from supplier", myConnection))
{
  myConnection.Open();

  using (SqlDataReader myReader = myCommand.ExecuteReader())
  {
    DataTable myTable = new DataTable();
    myTable.Load(myReader);
    myConnection.Close();

    dataGridView1.DataSource = myTable;
  }
}

Примечание: В настоящее время в вашем коде, если возникает исключение между DataSet ds = new DataSet() и ds.Dispose(), Dispose() не будет работать.Вы должны сделать using (DataSet ds = new DataSet()) { ... }, чтобы гарантировать, что Dispose() будет работать.Затем вы можете удалить ds.Dispose().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...