none
Обнуление памяти (очистка DataSet) после закрытия формы - WinForms C# RRS feed

  • Вопрос

  • Всем привет!
    Недавно столкнулся с неприятной проблемой: при закрытии вторичной формы не полностью очищается память 
    DataTable биндится к DataGridView, и по логике, после закрытия формы она должна полностью очистится и освободить память.
    Но не тут то было...
    Возможно я где-то неправ и что-то не понимаю или так и должно быть?
    Спасибо!

    В примере ниже создаётся "большой" DataTable, передается во вторичную форму и записывается в Грид.
    При открытии программы - она занимает 5 МБ;
    После открытия Form1 в оперативную память записывается 364 МБ;
    А после закрытия остаётся 90 МБ (почему не 5 ?)
    Я даже для тестов везде всё обнуляю и специально вызываю сборщик мусора.

    Вот пример основной формы (а именно вызов вторичной формы):

            private void btnShowFrm_Click(object sender, EventArgs e)
            {
                var ds = new DataSet();
                ds.Tables.Add("Test");
                ds.Tables["Test"].Columns.Add("Name", typeof (string));
     
                for (int i = 0; i < 1000000; i++)
                    ds.Tables["Test"].Rows.Add("aaa");
                
                ds.AcceptChanges();
     
     
                using (var frm = new Form1(ds))
                {
                    frm.ShowDialog();
                }
                
                ds = null;
                GC.Collect();
            }

    Вот пример формы, которая вызывается:

            private DataSet _ds;
     
            public Form1(DataSet ds)
            {
                InitializeComponent();
                _ds = ds;
                dataGridView1.DataSource = _ds.Tables[0];
            }
     
            private void Form1_FormClosed(object sender, FormClosedEventArgs e)
            {
                dataGridView1.DataSource = null;
                _ds = null;
                GC.Collect();
            }

    23 марта 2017 г. 14:44

Ответы

  • Объяснение в том, что ОС не освобождает память сразу, когда приложение от нее отказывается, если памяти другим приложениям хватает. Если другие приложения запросят много памяти, ОС заберет неиспользуемые блоки у вашего приложения.
    • Помечено в качестве ответа LightZ 23 марта 2017 г. 16:10
    23 марта 2017 г. 16:09
  • VadimTagil совершенно прав. В управляемых средах выделение памяти очень дёшево (потому что она сразу захватывается большим куском, а потом используется по мере необходимости), а её освобождение - дорого. Поэтому, как он уже написал, память не освобождается, пока её хватает в системе. Об этом очень часто забывают, когда обсуждают .NET/Java/Python/etc в сравнении с C/C++.
    • Помечено в качестве ответа LightZ 3 апреля 2017 г. 7:17
    3 апреля 2017 г. 0:27

Все ответы

  • Значение какого именно параметра вы смотрите? Если рабочий набор, это нормально - ОС сама решает, когда его уменьшить и на сколько. 
    23 марта 2017 г. 15:12
  • Память смотрю в диспетчере задач, по приложению
    23 марта 2017 г. 15:14
  • Какой *именно* параметр? Я понятия не имею, что у вас там включено. У меня в Win7 по умолчанию показывается частичный рабочий набор, который, видимо, не то что вам нужно. Как минимум надо смотреть параметр "Выделенная память", а также выделять/освобождать память несколько раз, чтобы получить значимые результаты.

    Что вы пытаетесь выяснить? Если вы подозреваете утечку памяти, это не проверяется диспетчером задач (только экспериментальные методы рулят).

    23 марта 2017 г. 15:37
  • Добрый день!


    Используйте

    Form.FormClosing Event

    https://msdn.microsoft.com/en-us/library/system.windows.forms.form.formclosing(v=vs.110).aspx

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                dataGridView1.DataSource = null;
                _ds = null;
                // GC.Collect(); // <- не нужно в конце метода его писать.
            }



    PS: У меня почему-то не получилось в дебаге пройти  в  Form1_FormClosed.
    Задачка интересная.

    PS2: Прочитайте про сборщик мусора https://habrahabr.ru/post/125968/
    или какой-нибудь другой источник найдите. Я читал Рихтера.

    23 марта 2017 г. 15:38
  • VadimTagil, пробовал отслеживать GC.GetTotalMemory(true), результаты другие, но всё равно обнуление не полное
    Возможно .NET решает сколько ему резервировать, а сколько освобождать, не знаю
    Цель моего топика - это найти объяснение и понять почему так происходит :)
    Т.к. на просторах интернета я не смог найти внятного объяснения
    Спасибо!
    • Изменено LightZ 23 марта 2017 г. 15:50
    23 марта 2017 г. 15:49
  • Остановится на FormClosed у меня получается
    Спасибо, про сборщик мусора я читал, и понимаю как он работает :)


    • Изменено LightZ 23 марта 2017 г. 15:52
    23 марта 2017 г. 15:51
  • Объяснение в том, что ОС не освобождает память сразу, когда приложение от нее отказывается, если памяти другим приложениям хватает. Если другие приложения запросят много памяти, ОС заберет неиспользуемые блоки у вашего приложения.
    • Помечено в качестве ответа LightZ 23 марта 2017 г. 16:10
    23 марта 2017 г. 16:09
  • Понял, спасибо Вам за разъяснения! 
    23 марта 2017 г. 16:10
  • VadimTagil совершенно прав. В управляемых средах выделение памяти очень дёшево (потому что она сразу захватывается большим куском, а потом используется по мере необходимости), а её освобождение - дорого. Поэтому, как он уже написал, память не освобождается, пока её хватает в системе. Об этом очень часто забывают, когда обсуждают .NET/Java/Python/etc в сравнении с C/C++.
    • Помечено в качестве ответа LightZ 3 апреля 2017 г. 7:17
    3 апреля 2017 г. 0:27