![]() |
|
Модераторы: Partizan, gambit |
![]()
|
|
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Здравствуйте. Есть программа, которая сканируют 7 Гб dbf файлов и вставляет инфу из них в другую СУБД. Сканирует их до тех пор, пока не вылетает исключение "Недостаточно системных ресурсов". Запустив програму заново и при этом запустив диспетчер задач,увидел что количество дескрипторов непрерывно растёт. Когда доходит почти до 30000 собственно и вылетает исключение. Нашёл в интренете инфу, что такая проблема возникает в связи с использованием многопоточности.(Реализую её через стандартную компоненту BackGrounWorker) А вот как её решить не совсем понятно. Помогите плз кто чем может.
|
|||
|
||||
| jonie |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5613 Регистрация: 21.8.2005 Где: Владимир Репутация: 6 Всего: 118 |
Вам нужно пройтись по всему коду в поисках объектов, которые вы создаете, классы которых наследуются от IDisposable [http://msdn.microsoft.com/en-us/library/system.idisposable.aspx]. Далее очень внимательно погуглить по этому интерфейсу и почитать MSDN. Думаю ресурсы как раз и текут и вас в силу недетерменированной природы деструкторов (финализаторов) в .NET - среда просто не успевает разрушать объекты, содержащие ссылки на неуправляемые ресурсы (дескрипторы), и винда глушит ваше приложение.... возможно также, что ошибка в библиотеках которые вы используете подобная имеется.
-------------------- Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет... |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
То есть если я правильно понял нужно реализовать IDisposable у всех самодельных классов?
|
|||
|
||||
| jonie |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5613 Регистрация: 21.8.2005 Где: Владимир Репутация: 6 Всего: 118 |
N1ko, нет неправильно. IDisposable нужен если вам нужно относительно детерменированное (читай "по запросу вами") очистка ресурсов например.
Вам надо пройтись по коду и найти места где вы используете классы, наследуемые от IDisposable ... например OleDBConnection наследуется...а дальше using-и использовать или try..finally В общем тут почитайте http://www.rsdn.ru/article/dotnet/GCnet.xml -------------------- Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет... |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Пробовал как вы сказали. Прочитал кучу статей. Уже по 5 раз прошёлся по всему коду. Сделал Dispose у всего что только можно. Ничего не получается ((
Вот выложил код, котрый непосредственно отвечает за считывание данных из одного DBF файла и вставляет их в SQLite. Програма в принципе работает без утечки в случае если я не закрываю OleDbReader а в final прописываю GC.Collect(); GC.WaitForPendingFinalizers(); Но где то на 600-700 мб просканеных дбф файлов програма начинает работать очень медленно. Судя по всему из-за сборщика мусора. Возможно глядя на код Вы найдёте ошибку. Буду очень благодарен за Вашу помощ.
Это сообщение отредактировал(а) N1ko - 26.5.2010, 12:29 |
|||
|
||||
| NightmareZ |
|
|||
![]() [хакер] ![]() ![]() Профиль Группа: Участник Сообщений: 699 Регистрация: 10.8.2006 Репутация: 1 Всего: 13 |
Я считаю, что этого делать не нужно. Нужно лишь вызывать Dispose. Ты уверен, что ошибка тут? Не пробывал отслеживать, где дескрипторы создаются и где уничтожаются? -------------------- NightmareZ.net - мой блог и сайт, мои проекты и прочий трэш Ely-Art.ru - наша маленькая домашняя арт-студия mugcraft.ru - кружки на любой вкус |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
А может ли быть утечка дескрипторов из-за того что я сначала создаю SQLiteCommand, создаю в нём параметры. Но не устанавливаю в них Value. А уже только потом меняю эти значения в цикле много раз. Для этого SQLiteCommand не делаю Dispose()
И ещё мне вообще не понятно почему когда я убираю _oleDBReader.Close(); _oleDBReader.Dispose(); но оставляю GarbageCollector всё работает нормально без утечек. Это сообщение отредактировал(а) N1ko - 27.5.2010, 11:03 |
|||
|
||||
| mrbrooks |
|
|||
![]() трололомен ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4259 Регистрация: 4.10.2006 Где: Дол Гулдур Репутация: 17 Всего: 306 |
а каков механизм сканирования? основан на DataReader, и если да, какой запрос его формирования? Добавлено через 4 минуты и 49 секунд этот код в блоке finally не нужен. Там достаточно _oleDBReader.Close(). И, следовательно, последний можно удалить из try catch вместе с _oleDBReader.Dispose() |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Для сканирования действительно использую DataReader. Но к сожалению не совсем понял, что Вы имели ввиду под запросом формирования.
А как же я в блок finally вставлю _oleDBReader.Close(), если у него область видимости очень маленькая. Ведь Oledbreader я создаю в блоке try. Это сообщение отредактировал(а) N1ko - 27.5.2010, 11:21 |
|||
|
||||
| mrbrooks |
|
|||
![]() трололомен ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4259 Регистрация: 4.10.2006 Где: Дол Гулдур Репутация: 17 Всего: 306 |
||||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Да. DbfFile - экземпляр класа, который хранит информацию о местонахождении DFB файла, его размере и тп. Метод ReadData() вытаскивает из него всю инфу.
В finally вряд ли получится закрывать Reader, потому что область видимости не позволяет.(Если оюъявить oledbreader перед блоком try) тогда в finally пишет ошибку "unassigned local variable" Это сообщение отредактировал(а) N1ko - 27.5.2010, 11:44 |
|||
|
||||
| mrbrooks |
|
|||
![]() трололомен ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4259 Регистрация: 4.10.2006 Где: Дол Гулдур Репутация: 17 Всего: 306 |
ну это не проблема - можно и так:
не нужен ни Close() ни finnaly вот это и интересно. думаю не 7Gb? |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Нет файлов очень много, каждый из которых от 20 до 400 кб.
В общем суть програмы следующая . Пользователь указывают папку, которую нужно просканировать на наличие DBF файлов, вытащить из них инфу и вставить в СУБД. Делаю я это посредством рекурсии. Соответственно DbfFile.ReadData() работает не с 7 Гб одновременно а работает с маленькими объёмами А можно ли как то очистить ресурсы выделенные под String после их затирания? Как я уже писал всё время использую один и то же SQLiteCommand, затирая Value для всех параметров и ставя на их место новые. Это сообщение отредактировал(а) N1ko - 27.5.2010, 12:10 |
|||
|
||||
| mrbrooks |
|
|||
![]() трололомен ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4259 Регистрация: 4.10.2006 Где: Дол Гулдур Репутация: 17 Всего: 306 |
string.Empty? В целом ясно. Идея в принципе работоспособная (настораживает только рекурсия - net обладает отличной библиотекой по работе с каталогами). Имхо проблема, скорее всего просто в проектировании. По данному примеру тяжело судить о том что творится в целом. Подозреваю, что работа с базами у вас свалена вся в один класс, a стоило бы разделить работу с сущностями по отдельным, etc |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Нет Я уже на этом прокололся недавно. И всё разграничил по сущностям. Для базы создал классы реализующие обёртку для самой БД, таблиц, полей, операций вставки, селекта и тп. В этом смысле вроде бы подход уже нормальный. Хотя изначально всё действительно было свалено в одну кучу.
|
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
А можно ли как то более точно отследить на каком этапе у меня создаются дескрипторы, нежели запускать програму и смотреть на диспетчер?
|
|||
|
||||
| mihryak |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 731 Регистрация: 28.4.2007 Где: С-Пб Репутация: 10 Всего: 36 |
N1ko, .net memory profiler
|
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Вот за это Вам огромное спасибо. Действительно помогло. Утечка идёт от String как я и предполагал. Насколько я понимаю string - ом должен занимаеться сборщик мусора автоматически. Но судя по всему он этого делать не успевает. Можно ли как то вучную это делать? String.Empty не помагает поскольку судя по всему из памяти строка не удаляется.
Это сообщение отредактировал(а) N1ko - 28.5.2010, 11:08 |
|||
|
||||
| uranpro |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 571 Регистрация: 7.5.2008 Где: Moscow city Репутация: нет Всего: 1 |
вот бы код рекурсии увидеть)...
Добавлено через 2 минуты и 28 секунд Конец жизни переменной: - до конца области видимости в Debug - до последнего упоминания ее в коде в Release http://forum.vingrad.ru/forum/topic-301328.html © -------------------- I want a perfect soul |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
uranpro ,вот собственно рекурсия. Метод ScanDbfFiles сканирует заданую папку на наличие в ней ДБФ файлов. Если таковые там есть, откурывается ДБФ соединение и с читывается вся инфа с файлов. Второй метод ScanFolder сканирует папку на наличие в ней других папок.
Вот такая вот реализация рекурсии... Это сообщение отредактировал(а) N1ko - 31.5.2010, 10:53 |
|||
|
||||
| mrbrooks |
|
|||
![]() трололомен ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4259 Регистрация: 4.10.2006 Где: Дол Гулдур Репутация: 17 Всего: 306 |
N1ko,
используйте перегруженный метод DirectoryInfo.GetFiles(String, SearchOption), где SearchOption есть перечисление, характеризующее, искать ли файл в текущем каталоге, или еще и во вложенных. Типа этого:
и никакой рекурсии. |
|||
|
||||
| N1ko |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Если так делать, возникают дополнительные сложности. Ну допустим просканим мы таким способом заданную папку, соответственно ссылки на все файлы будут находиться в одном хранилище и их будет очень много. Для того что бы прочитать ДБФ файл нужно открыть соединение с папкой, в которой он находится. А допустим таких фалов 20 и они распологаются не подряд. Тогда нам прийдётся создавать и открывать несколько раз одно и то же самое соединение. При преходе к каждому новому файлу прийдётся сверять его месторасположение по сравнению с предыдущим и тп. Считаю что проще будет всё таки рекурсией всё сделать. И в основе перегруженного метода с двумя параметраме наверняка используюется всё та же рекурсия. Хотя в этом и не особо уверен.
Это сообщение отредактировал(а) N1ko - 31.5.2010, 11:37 |
|||
|
||||
| PashaPash |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 9 Всего: 49 |
N1ko, так сгруппируй результаты поиска по Path.GetDirectory
|
|||
|
||||
| PashaPash |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 9 Всего: 49 |
N1ko, кстати, а где в первом примере ты открываешь и закрываешь соединение?
|
|||
|
||||
| N1ko |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 383 Регистрация: 30.12.2007 Где: Киев Репутация: нет Всего: нет |
Во втором примере как раз видно что открываю я соединенеие перед использованием функции InsertFromDbf
и сооответственно закрываю его после её завершения.
В самой функции этого делать не требуется, поскольку для каждого дбф нету смысла открывать и закрывать одно и то же соединение. Это сообщение отредактировал(а) N1ko - 1.6.2010, 12:42 |
||||
|
|||||
![]()
|
| Прежде чем создать тему, посмотрите сюда: | |
|
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, Partizan, PashaPash. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | .NET для новичков | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |