На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> Куда ушла память?
    Господа! Так случилось, что волею судьбы (а точнее сказать по желанию начальства) я теперь пишу на vb.net. Поскольку с Basic'ом и OLE DB я до не давнего времени не сталкивался вообще, кое-что у меня, конечно, выходит криво.  Теперь собственно сам сабж: пишу милую прогу на vb.net для БД Access. Кучка форм, OLE DB, пара-тройка датасетов, которые создаются и заполняются программно. Все чинно, мило и что самое интересное - ВСЕ РАБОТАЕТ!!! Но! Недавно в диспетчере задач обратил внимание на количество памяти, которую жрет моя прога. Оказалось - всего ничего - около100 Mb. Тут я, конечно, слегка расстроился, а потому решил спросить совета у бывалых джедаев. Дело в том, что я как доверчивый чукотский юноша в своей проге ничего(коннекшн, датасет и т.п.) не закрываю (кроме форм) и не убиваю (я имею в виду vb-шный SET ... = Nothing). Делаю я это оттого, что ни в одном из виденных мной примеров ничего подобного я не встретил и решил, что dotnet настолько модная среда разработки, что делает это сама (например при закрытии формы).

    Итак, подскажите, плз:
    1) Что может жрать столько памяти?
    2) Надо ли закрывать коннекшены?
    3) Надо ли явно убивать датасеты после их заполнения и вывода данных в dbgrid (этого бы делать не хотелось, т.к. они (датасеты) нужны мне для дальнейшей работы).

    Заранее премного благодарен.
      1) Сколько датасетов? 3-4? Дарагой! Так нельзя - датасет уж очень охоч до памяти! + его обслуга (DataAdapters, Commands). Вобщем так, сделай 1 глобальный датасет, всё же меньше жрать будет. Заполни его в начале отдельными DataAdapter, которые сразу уничтож (либо using, либо .Dispose()). Update по необходимости, с помощью своих DA.
      После начально инициализации полезен garbage collect.
      2)А как ты с ними работаешь? Если прочитал при запуске программы, записал при выходе, то закрывай на время работы, иначе смотри сам. Но если коннект закрыт и сделать DataAdapter.Fill, Update  то коннект откроется на время вызова, а потом закроется - а это классная пожиралка всех ресурсов. Поэтому, если выполняется несколько Fill/Update подряд, то коннект надо открыть до и закрыть после всех.
      3)см 1.

      Я делаю как описал в п. 1. Прога с таким датасетом (там данные из БД примерно равной по размеру структуры и данных Northwind) занимает в памяти 25М при запуске. Если открыть штук пять форм (разных классов) то будет около 100М, итд. Никто не жалуется, все равно всё ненужное в своп уходит :)

      Кстати set ... = nothing по-моему ничего не даёт, это как в с++
      ExpandedWrap disabled
        <br>char *s=new char[1000];<br>s=NULL;//это и есть nothing<br>//detected memory leaks! :)<br>

      но точно сказать не могу, так как с VB мало работал
        Глобальный датасет это пожалуй true. Тогда встречный вопрос: как (где?) в VB.NET объявить глобальную переменную? Такую, чтоб не внутри какого-то класса, а поверх всех, МЕГАглобальную. Ведь, как я понимаю, если я просто объявлю ее в каком-либо классе как Public, и потом в какой-то другой форме буду создавать объект того класса, то это ничего не решит, т.к. это будут разные объекты. А создавать связь между формами шибко геморройно. Или я чего-то недопонимаю?
          Цитата Леший, 11.08.03, 07:47:08
          Глобальный датасет это пожалуй true. Тогда встречный вопрос: как (где?) в VB.NET объявить глобальную переменную? Такую, чтоб не внутри какого-то класса, а поверх всех, МЕГАглобальную. Ведь, как я понимаю, если я просто объявлю ее в каком-либо классе как Public, и потом в какой-то другой форме буду создавать объект того класса, то это ничего не решит, т.к. это будут разные объекты. А создавать связь между формами шибко геморройно. Или я чего-то недопонимаю?

          В .NET все должно быть внутри классов. Если ты хочешь чтобы переменная была одна на все экземпляры - объяви ее как Static.
            У кого-нить есть пример работы с GC. Я вызвал q = GetTotalMemory(1) и он мне вернул 38'094'980 байт. Попробовал Collect() - память не освободилась. Пробовал даже так:

            Conn.Close()
            Conn.Dispose()
            Comm.Dispose()
            ds.Dispose()
            Conn = Nothing
            Comm = Nothing
            ds = Nothing
            q = GetTotalMemory(1)
            Collect()

            - с тем же результатом. Время впадать а отчаянье. А не хотелось бы.
              Делаю совсем просто: две формы. На form2 один батон, нажали - открылась form1. На form1 две кнопки: батон1 и батон2. Батон1 - открываем БД, выводим в датагрид; батон2 - Kill Them All !!!

              ExpandedWrap disabled
                <br>Imports System.GC<br>Public Class Form2<br>    Inherits System.Windows.Forms.Form<br><br>    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click<br>        Dim rrr As New Form1()<br><br>        rrr.ShowDialog()<br>        rrr.Dispose()<br>        Collect()<br>        WaitForPendingFinalizers()<br>        Collect()<br>    End Sub<br>End Class<br>


              ExpandedWrap disabled
                <br>mports System.Data.OleDb, System.GC<br>Public Class Form1<br>    Inherits System.Windows.Forms.Form<br><br>    Public strConn, sSQL, srcFile As String<br>    Public Comm As OleDbCommand<br>    Public ds As DataSet<br>    Public Conn As OleDbConnection<br>    Public Ad As OleDbDataAdapter<br>Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click<br><br>        Dim q As Long<br><br>        ds = New DataSet()<br><br>        DataGrid1.DataSource = ds 'Контрол Grid связываем с объектом DataSet<br><br>        sSQL = "SELECT * FROM SSP"<br>        srcFile = "form2.mdb"<br>        Try<br>            'Создаём и открываем соединение<br>            Conn = New OleDbConnection()<br>            Conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source='" & srcFile & "'"<br>            Conn.Open()<br><br>            Comm = New OleDbCommand(sSQL, Conn) 'Создаём команду выборки данных<br>            Comm.Connection = Conn 'Указываем команде нужное соединение<br><br>            Ad = New OleDbDataAdapter() 'Создаём адаптер данных<br>            Ad.SelectCommand = Comm 'Указываем команду выборки данных<br>            Ad.Fill(ds, "SSP") 'Заполняем DataSet. <br>            DataGrid1.DataMember = ds.Tables("SSP").TableName<br><br>            Conn.Close()<br>        Catch ex As Exception<br>            MsgBox("Тип ошибки: " & ex.GetType.FullName & vbCrLf & ex.Message)<br>        End Try<br>    End Sub<br><br>    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click<br>        Close()<br>        Conn.Dispose()<br>        Comm.Dispose()<br>        ds.Clear()<br>        Conn = Nothing<br>        Comm = Nothing<br>        ds = Nothing<br>        DataGrid1.Dispose()<br>        Collect()<br>        WaitForPendingFinalizers()<br>        Collect()<br>    End Sub<br>End Class<br>


              Нажимаем батон1, потом батон2. Прога как занимала 70 метров в памяти, так и занимает!!!
              ???
                Она занимает 70М памяти до нажатия  1 батона? Если да, то я не знаю в чём дело. Если нет, то какой объём загружаемых данных?
                  До нажатия 1 батона прога занимает 9 метров. После - 70. "Form2.mdb" весит 25 метров.
                  Там 6 таблиц, в таблице SSP 30 тыс. записей.
                    Это "нормально"
                      Согласен с andrey.
                      Это общее явление для GC-платформ. Твой коллект - всего лишь инициация процесса, но не гарантия того что память будет освобождена. А сборщик ее освобождает не тогда когда ее "много занято", а когда он считает, что "ее стало не хватать". Вообще алгоритм сборки мусора в НЕТ значительно сложнее и по многим оценкам эффективней чем в Яве. Майкрософт им дорожит настолько, что даже в CLI включила сильно упрощенный вариант. Достаточно немало о нем можно прочитать в книге Рихтера.
                        Ну если очень хочется поменьше оперативки, то не используй динамические структуры, DataSet и DataTable, каждой таблице сопоставь класс (запись в таблице) и коллекцию этих классов. Тогда размер будет поменьше, зато работы поболее.

                        ExpandedWrap disabled
                          <br>CREATE TABLE TestTab(<br>ID int primary key,<br>fld1 varchar(100),<br>....<br>)<br>

                        ExpandedWrap disabled
                          <br>internal class TestTabRecord{<br>public int ID;<br>public string fld1;<br>....<br>}<br>internal class TestTabRecorCollection:CollectionBase {..}//генерится генератором коллекций из .NET Fw SDK, где то на форуме я писал где его искать<br>

                        Потом читаем таблицу с помощью DataReader и заполняем коллекцию.
                        Дальше всё работает также как и с DataTable, только нельзя связать контролы с даннми в IDE, придётся делать в коде.
                        НО!!!! DataReader ОБЯЗАТЕЛЬНО нужно закрывать как можно раньше, так как он эксклюзивно захватывает Connection.
                          Проблема более менее решилась, когда я сделал форму модальной. Тогда все просто:
                          сразу после отработки формы убиваю ее и вызываю GC.

                          Imports  System.GC

                                 frmSelSSP.ShowDialog()
                                 frmSelSSP = Nothing
                                 Collect()
                                 WaitForPendingFinalizers()
                                 Collect()

                          А как тогда поступать, если форма не модальна? Если это MDIChild к примеру?
                            Точно также - забить в указатель NULL. Тогда ссылок не неё не бедет, а при закрытии она удалится. Чтобы вовремя вызвать GC.Collect() можно подчепится к событию формы (ДО забивания NULLом)
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,0365 ]   [ 16 queries used ]   [ Generated: 27.04.24, 15:46 GMT ]