2010-06-29 4 views
5

При использовании SqlConnection важно всегда закрывать его при использовании - либо .Close(), либо помещать SqlConnection в «использование». К несчастью, люди, в том числе и я, как правило, забывают об этом, и именно здесь сборщики мусора ненадолго спасают меня, пока я не забуду слишком часто закрывать свои подключения или увеличивать число пользователей, использующих приложение.Обнаружение, если вызывается сборщик мусора (.Net)

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

Другой способ может быть наследованием SqlConnection и поместить таймер на его инициализатор и проверить, сколько времени потребовалось для закрытия соединения при утилизации класса. Мне не очень нравятся таймеры, но идея придумала это.

Возможно, есть третий и даже более умный способ ко всему этому ... Что бы вы порекомендовали?

+0

'либо .close() или размещения SqlConnection в «использовании» ** НЕТ НЕТ НЕТ! **. Закрытие() недостаточно само по себе. В этом весь смысл конструкции 'using': слишком много людей также забывают, что ваш .Close() _must_ находится в конечном блоке. –

ответ

2

Одно эмпирическое правило говорит: «Если вам нужно подумать о сборщике мусора, вы, вероятно, что-то сделаете неправильно». (Конечно, есть и другие большие пальцы ...)

Мне кажется, что обеспечение того, что соединения закрыты либо явно, либо через using и finally блоки - лучший маршрут.

Очевидно, что вы уже понимаете эти методы ... поэтому, возможно, один раз в коде и возможный рефакторинг - это все, что вам нужно.

0

Если вы забудете распоряжаться, объект будет завершен. Нет способа контролировать время, в которое это происходит, и вы также не можете узнать, завершен ли объект. Отдельный поток должен быть создан для завершения объектов, поэтому он замедляет ваше приложение. Вот почему вы хотите избавиться. Во всех классах в среде, реализующей IDisposable, делается вызов GC.SuppressFinalize, поэтому объект не завершен.

У вас нет возможности контролировать это поведение. Если ваш объект больше не используется, он будет автоматически собран. Все, что вы можете сделать, чтобы остановить это, - это вызов GC.SuppressFinalize, но я бы не рекомендовал этого, потому что, если бы вы тогда забыли, вы были бы прикованы к жизни.

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

+0

Я бы сказал, что «обычно будет завершено». Ситуации могут легко возникать, когда неспособность «Dispose» объекта, который привязан к чему-то статическому, будет препятствовать тому, чтобы этот объект * или что-либо, к которому он имеет прямую или косвенную ссылку *, из * когда-либо *, стал подходящим для сбора мусора. – supercat

4

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

Лучше всего обнаружить эти проблемы с помощью инструмента статического анализа кода, который имеет возможность обнаруживать все места в коде, где вы забыли установить соединение. Существует один встроенный в in Visual Studio, или вы можете использовать FxCop.

Чтобы помочь вам не забыть расположени связь, это хорошая идея:

  • Храните код подключения к БД в один слой/сборки/модуля, поэтому не разбросаны по проектам.
  • Утилиты для выполнения команд SQL и возврата результатов; поэтому вы не создаете SQLConnection больше мест, чем вам нужно.
  • Не забывайте использовать C# using construct.
+2

+1 лучший способ приблизиться к этому - это получить основную причину и ликвидировать соединения. –

1

Если ваше приложение использует пул соединений SQL (по умолчанию), это не имеет значения, поскольку соединения повторно используются и не закрываются при вызове .Close() или оставьте блок использования() {} ,

http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx

Чтобы ответить на ваш вопрос, я не считаю, что это событие для сбора GC, однако это не имело бы значения, если бы было, потому что вы никогда не знали бы, если GC решил переработать свой объект на этой коллекции pass (не все объекты очищаются из-за алгоритма генерации).

Я бы также избегал попыток использовать таймеры и «проверки», так как вы, вероятно, будете ссылаться на объект и не позволять ему когда-либо удаляться.

+0

Но это имеет значение, поскольку если соединения не закрыты, они не возвращаются в пул, поэтому они не будут повторно использоваться повторно. Это может привести к исчерпанию пула соединений или к потреблению ценных ресурсов, вызывающих проблемы. –

+1

Согласовано, но точка OP хочет знать «когда» происходит сбор мусора. Я хотел сказать, что сбор соединений sql не будет происходить с пулом. Единственное решение состоит в том, чтобы фактически исправить и обеспечить. Вызывается вызов close(), а не полагается на событие сбора GC или проверку таймера. – David

0

Во-первых, если вы даже рассматриваете использование GC, у вас есть серьезные проблемы где-то. Я предлагаю, чтобы лучший способ гарантировать, что ваши кодовые вызовы Close - это модульный тест вашего кода с использованием таких методов, как mocking. Если ваш юнит-тест указывает на то, что был вызван Close, ваш код верен, и вам не нужно делать что-то ненужное, например, с помощью Garbage Collector.

Во-вторых, если вы по-прежнему настаивают на идя проверки выполнения маршрута, то только вещь, которую вы должны даже рассмотреть возможность сделать это зацепив StateChange событие SqlConnection. Это загорится, если ConnectionState изменится с Open на Closed, например.

1

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

Просто создайте weak reference для объекта-пустышки. Если вы посмотрите на слабую ссылку позже, и объект больше не alive, вы можете предположить, что произошла сборка мусора.

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

+0

В этом весь смысл, вам нужно избавиться от финализации. Если вы просто храните слабый реф и проверяете, не случилось ли это, вы уже опоздали. (Сбор мусора приходит после завершения). –

+0

Да, конечно. Как указано в последнем предложении, я только хотел ответить «Обнаружение, если был вызван сборщик мусора».Вы не должны писать код, который утечки ресурсов в первую очередь. И это можно эффективно избежать, выполняя статический анализ и профилирование во время выполнения. –

Смежные вопросы