Недостаточно быстрое освобождение очереди завершения

#c# #oracle #dispose #freeze #finalize

#c# #Oracle #утилизировать #замораживание #завершить

Вопрос:

У меня есть приложение Windows на c # 3.5 Framework, которое работает с базой данных Oracle, расположенной на сервере.

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

Исходя из структуры существующей программы, каждый раз, когда изменяется поле со списком, открывается около 20 отдельных подключений к БД. Сначала вызывается около 8 для сохранения данных с разных вкладок в их правильную таблицу. Содержимое каждой вкладки передается в класс DB для сохранения данных этой вкладки. Во-вторых, выполняется около 8 вызовов DB для загрузки вкладок из таблиц на основе выпадающего списка.

Чтобы пояснить, это все равно что выбрать поле со списком на любой вкладке, которое изменяет модель автомобиля. Тогда каждая вкладка будет содержать такие вещи, как «параметры интерьера», «параметры движка» и т.д.

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

Процесс, в целом, довольно надежный. Время сохранения / загрузки стремительно сокращается. Я могу переключаться между двумя разными значениями в выпадающем списке с почти мгновенным сохранением / загрузкой данных.

ЗАТЕМ ВОЗНИКАЕТ ПРОБЛЕМА

Если я буду вращаться туда-сюда достаточно быстро (что также сделали несколько пользователей), вся программа зависнет. Никакого сбоя, просто зависает.

Повторив это в среде отладки, я обнаружил, что она всегда останавливается на одной и той же строке кода (простое назначение набора записей (например, CarModelInterior.Примечания = Преобразовать.toString(myReader[6]);)

Затем я обнаружил, что поток сборщика мусора (GC) выполнялся в фоновом режиме, но также каждый раз останавливался в одном и том же месте.

Приступаем к установке мониторов памяти / производительности RED-Gate.

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

Введите мои предположения.

Я думаю, что либо открыто слишком много соединений, которые завершаются недостаточно быстро, либо где-то происходит блокировка.

Что я могу сказать, так это то, что ВСЕ (каждый без исключения долбаный) мои вызовы DB во всей программе используют инструкцию «USING», поэтому вся утилизация завершается автоматически. Кроме того, ВСЕ (как и в да, я проверил все приложение), ВСЕ вызовы DB выполняются в основном потоке. Таким образом, все 20 или около того вызовов DB, выполняемых для каждого изменения значения combobox, выполняются по порядку. Это устранило возможность блокировки, по крайней мере, в той мере, в какой это было возможной проблемой с одним потоком.

Что у меня осталось? На данный момент я так много гуглил, что сдался и разместил здесь. Возможно ли, что очередь завершения обрабатывается недостаточно быстро? Есть еще идеи?

Комментарии:

1. вопрос в том, почему (и с какими объектами?) заполняется ли очередь завершения в первую очередь? Если вы распоряжаетесь своими ресурсами, вызов Dispose должен выполнить GC.SuppressFinalize() , который позволил бы избежать этой проблемы.

2. Broken Glass сделал проницательное наблюдение. Кроме того, существуют ли какие-либо блокирующие примитивы, которые могут привести к взаимоблокировке общего ресурса? Возможно, это на уровне доступа к данным (который вы не упомянули; что это?)

3. Все значения, перечисленные в программе Red Gate, фильтруются по «Объектам, которые не удаляются», и все они являются объектами OracleCommand. Тот, который находится в верхней части списка, когда он зависает (с несколькими снимками памяти, подтверждающими, что он не очищает очередь), является SQL удаления. Поскольку я могу воспроизвести ошибку, и она однопоточная, как это может быть ошибкой блокировки? (невинный вопрос)

4. Кроме того, во всех операторах используется: using (MyConnection = new OracleConnection(ConnectDB)). Так что это не причина для развертывания моего собственного dispose. Строка подключения к Oracle DB — это просто источник данных, идентификатор пользователя и пароль.

5. вы также удаляете OracleCommands или только соединение? Если нет, то это может быть вашей проблемой (проще всего использовать их в блоке using).

Ответ №1:

Команда OracleCommand должна быть удалена до того, как ресурсы могут быть восстановлены. DbCommand, часто являющийся базовым классом для объектов Command, реализует IDisposable. Для сравнения, System.Data.SqlClient.SqlCommand, похоже, не требует удаления, поэтому это может заставить разработчиков забыть, что многие реализации DbCommand требуют удаления. Если команды не будут удалены, то сборщик мусора в конечном итоге освободит неуправляемые ресурсы, вызвав метод Finalize (при условии, что реализация OracleCommand вашим клиентом Oracle переопределяет object.Завершить).