Обнаружение, если сборщик мусора был вызван (.Net) - PullRequest
5 голосов
/ 29 июня 2010

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

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

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

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

Ответы [ 6 ]

4 голосов
/ 29 июня 2010

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

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

Чтобы помочь вам не забыть избавиться от соединения, рекомендуется:

  • Храните весь код соединения с БД в одном слое / сборке / модуле, чтобы он не рассеивался по проектам.
  • Имеют служебные методы для выполнения команд SQL и возврата результатов;так что вы не создаете SQLConnection больше мест, чем вам нужно.
  • Не забудьте использовать C # используя конструкцию .
2 голосов
/ 29 июня 2010

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

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

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

1 голос
/ 29 июня 2010

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

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

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

1 голос
/ 29 июня 2010

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

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

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

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

0 голосов
/ 29 июня 2010

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

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

0 голосов
/ 29 июня 2010

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

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

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

...