Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.118.0.240] |
|
Сообщ.
#1
,
|
|
|
Господа! Так случилось, что волею судьбы (а точнее сказать по желанию начальства) я теперь пишу на vb.net. Поскольку с Basic'ом и OLE DB я до не давнего времени не сталкивался вообще, кое-что у меня, конечно, выходит криво. Теперь собственно сам сабж: пишу милую прогу на vb.net для БД Access. Кучка форм, OLE DB, пара-тройка датасетов, которые создаются и заполняются программно. Все чинно, мило и что самое интересное - ВСЕ РАБОТАЕТ!!! Но! Недавно в диспетчере задач обратил внимание на количество памяти, которую жрет моя прога. Оказалось - всего ничего - около100 Mb. Тут я, конечно, слегка расстроился, а потому решил спросить совета у бывалых джедаев. Дело в том, что я как доверчивый чукотский юноша в своей проге ничего(коннекшн, датасет и т.п.) не закрываю (кроме форм) и не убиваю (я имею в виду vb-шный SET ... = Nothing). Делаю я это оттого, что ни в одном из виденных мной примеров ничего подобного я не встретил и решил, что dotnet настолько модная среда разработки, что делает это сама (например при закрытии формы).
Итак, подскажите, плз: 1) Что может жрать столько памяти? 2) Надо ли закрывать коннекшены? 3) Надо ли явно убивать датасеты после их заполнения и вывода данных в dbgrid (этого бы делать не хотелось, т.к. они (датасеты) нужны мне для дальнейшей работы). Заранее премного благодарен. |
Сообщ.
#2
,
|
|
|
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 по-моему ничего не даёт, это как в с++ <br>char *s=new char[1000];<br>s=NULL;//это и есть nothing<br>//detected memory leaks! :)<br> но точно сказать не могу, так как с VB мало работал |
Сообщ.
#3
,
|
|
|
Глобальный датасет это пожалуй true. Тогда встречный вопрос: как (где?) в VB.NET объявить глобальную переменную? Такую, чтоб не внутри какого-то класса, а поверх всех, МЕГАглобальную. Ведь, как я понимаю, если я просто объявлю ее в каком-либо классе как Public, и потом в какой-то другой форме буду создавать объект того класса, то это ничего не решит, т.к. это будут разные объекты. А создавать связь между формами шибко геморройно. Или я чего-то недопонимаю?
|
Сообщ.
#4
,
|
|
|
Цитата Леший, 11.08.03, 07:47:08 Глобальный датасет это пожалуй true. Тогда встречный вопрос: как (где?) в VB.NET объявить глобальную переменную? Такую, чтоб не внутри какого-то класса, а поверх всех, МЕГАглобальную. Ведь, как я понимаю, если я просто объявлю ее в каком-либо классе как Public, и потом в какой-то другой форме буду создавать объект того класса, то это ничего не решит, т.к. это будут разные объекты. А создавать связь между формами шибко геморройно. Или я чего-то недопонимаю? В .NET все должно быть внутри классов. Если ты хочешь чтобы переменная была одна на все экземпляры - объяви ее как Static. |
Сообщ.
#5
,
|
|
|
У кого-нить есть пример работы с 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() - с тем же результатом. Время впадать а отчаянье. А не хотелось бы. |
Сообщ.
#6
,
|
|
|
Делаю совсем просто: две формы. На form2 один батон, нажали - открылась form1. На form1 две кнопки: батон1 и батон2. Батон1 - открываем БД, выводим в датагрид; батон2 - Kill Them All !!!
<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> <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 метров в памяти, так и занимает!!! ??? |
Сообщ.
#7
,
|
|
|
Она занимает 70М памяти до нажатия 1 батона? Если да, то я не знаю в чём дело. Если нет, то какой объём загружаемых данных?
|
Сообщ.
#8
,
|
|
|
До нажатия 1 батона прога занимает 9 метров. После - 70. "Form2.mdb" весит 25 метров.
Там 6 таблиц, в таблице SSP 30 тыс. записей. |
Сообщ.
#9
,
|
|
|
Это "нормально"
|
Сообщ.
#10
,
|
|
|
Согласен с andrey.
Это общее явление для GC-платформ. Твой коллект - всего лишь инициация процесса, но не гарантия того что память будет освобождена. А сборщик ее освобождает не тогда когда ее "много занято", а когда он считает, что "ее стало не хватать". Вообще алгоритм сборки мусора в НЕТ значительно сложнее и по многим оценкам эффективней чем в Яве. Майкрософт им дорожит настолько, что даже в CLI включила сильно упрощенный вариант. Достаточно немало о нем можно прочитать в книге Рихтера. |
Сообщ.
#11
,
|
|
|
Ну если очень хочется поменьше оперативки, то не используй динамические структуры, DataSet и DataTable, каждой таблице сопоставь класс (запись в таблице) и коллекцию этих классов. Тогда размер будет поменьше, зато работы поболее.
<br>CREATE TABLE TestTab(<br>ID int primary key,<br>fld1 varchar(100),<br>....<br>)<br> <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. |
Сообщ.
#12
,
|
|
|
Проблема более менее решилась, когда я сделал форму модальной. Тогда все просто:
сразу после отработки формы убиваю ее и вызываю GC. Imports System.GC frmSelSSP.ShowDialog() frmSelSSP = Nothing Collect() WaitForPendingFinalizers() Collect() А как тогда поступать, если форма не модальна? Если это MDIChild к примеру? |
Сообщ.
#13
,
|
|
|
Точно также - забить в указатель NULL. Тогда ссылок не неё не бедет, а при закрытии она удалится. Чтобы вовремя вызвать GC.Collect() можно подчепится к событию формы (ДО забивания NULLом)
|