Как уменьшить объем памяти, используемой пулом соединений Sql в программе C#



У меня есть программа на C#, которая действует как многопоточный веб-сервер. Он выполняет множество операций по обработке Xml-структур, хранящихся в базе данных Sql Server.



Поскольку размер этих Xml-структур увеличивается, я нахожу, что приложение работает без памяти.



Я развернул профилировщик памяти ANTS, чтобы видеть, что происходит, и мне удалось уменьшить количество больших строк, удерживаемых в памяти во время обработки, и немного улучшить ситуацию.

Однако теперь я остался с фрагментированным большая куча объектов, вызванная большими массивами байтов, хранящихся в пуле соединений. Большие массивы байтов



TdsParserStateObject._bTmp
in TdsParser._physicalStateObj
in SqlInternalConnectionIds._parser
in DbConnectionInternal[0]
in DbConnectionPool._objectList


Я на 99,9% уверен, что использую только соединения в операторах using, хотя я держу одно соединение на поток открытым, пока поток работает (что предназначено для оптимизации, но я подозреваю, что это ухудшает ситуацию).



Есть ли что-нибудь, что я могу сделать для соединения, чтобы уменьшить объем памяти, которую оно содержит (кроме закрытия или удаления это)?

Или я должен просто всегда закрывать или утилизировать каждое соединение немедленно при каждом использовании?



[позже - согласно моему комментарию]
Я переработал код, чтобы использовать новое соединение для каждого доступа к базе данных, а затем избавиться от него (за исключением транзакций, конечно, где я использую одно и то же соединение от начала до конца транзакции и удаляю его вместе с транзакцией).



Даже когда программа находится в режиме ожидания (т. е. не имеет используемых соединений), в программе все еще есть соединения. пул соединений, занимающий большие объемы памяти и вызывающий фрагментацию.



Почему удаленное соединение должно содержать 58 МБ памяти в пуле соединений?



[Еще Позже]
У меня есть решение, которое не позволяет пулу соединений Sql Server фрагментировать большую кучу-это определить, какие соединения, вероятно, будут иметь огромный буфер, и отметить их для удаления из пула при удалении, используя



SqlConnection.ClearPool (соединение)



В настоящее время я делаю это в довольно хитрый способ, путем подклассов DataReader и обнаружения, если какие-либо из возвращенных полей имеют размер более 10 МБ.



Приветствуются предложения относительно лучшего способа обнаружения соединений, имеющих большие буферы.



Обратите внимание, что я отклонил изменения, чтобы открыть и удалить соединение на каждом доступе к базе данных, так как отслеживание того, какое соединение использовать, находясь внутри транзакции (очевидно, это должна быть транзакция), занимало мою голову.



Соединение открытие в начале потока и закрытие в конце-это нормально, так как почти все потоки недолговечны (будучи ответом на один веб-запрос). Исключение составляют пакетные процессы, которые, вероятно, работают в контексте одной транзакции в любом случае.

696   2  

2 ответов:

Нет необходимости держать соединение открытым, когда вы используете ADO.NET соединения будут объединены для вас по умолчанию (если вы не отключили объединение самостоятельно) и ADO.NET будет делать все управление бассейном. Вам даже не нужно беспокоиться о разных учетных данных пользователя и т. д. поскольку соединения объединяются в пул только в том случае, если параметры соединения идентичны. С точки зрения использования памяти удаление соединения может быть только полезным.

Подробнее об этом:

Ответ Шимона хорош, до определенного момента, поэтому я проголосовал за него.

Однако есть ряд вопросов, которые его ответ не решает. Всякий раз, когда очень большие данные (в моем случае одно текстовое поле, содержащее около 10 МБ Xml) извлекаются через SqlConnection, внутренние буферы соединения кажутся очень большими.

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

Единственный способ, который я нашел, чтобы предотвратить это, - это обнаружить SqlConnections, которые использовались для больших данных, и удалить их из пула соединений перед их удалением.

Как видно из более поздних правок в моем вопросе, я не нашел элегантного способа определить, является ли внутренний буфер SqlConnection большим или нет, просто очень неэлегантным, путем создание подклассов DataReader и обнаружение, если какие-либо из возвращенных полей имеют размер более 10 МБ!

Comments

    Ничего не найдено.