2010-06-29 2 views
5

SqlConnection을 사용할 때는 .Close() 또는 "using"에 SqlConnection을 배치하여 항상 닫는 것이 중요합니다. 불행히도, 나 자신을 포함한 사람들은 이것을 잊어 버리는 경향이 있습니다. 이것은 가비지 수집자가 너무 자주 내 연결을 닫지 않았거나 응용 프로그램을 사용하는 사람들의 수가 늘어날 때까지 잠시 동안 나를 구해줍니다.가비지 수집기가 호출되었는지 감지 (.Net)

가비지 수집기가 SqlConnection을 폐기했는지 여부를 감지하는 방법을 알고 싶습니다. SqlConnection이 더 이상 사용되지 않았거나 SqlConnection이 올바른 방법으로 종료 된 것으로 판단 되었기 때문입니다.

다른 방법으로는 SqlConnection을 상속 받아 초기화 프로그램에 타이머를 넣고 클래스를 삭제할 때 연결이 닫히는 데 걸린 시간을 확인할 수 있습니다. 나는 타이머를 정말 좋아하지 않지만 이것을 쓰는 동안 아이디어가 떠올랐다.

어쩌면이 모든면에서 세 번째로 더 똑똑한 방법이있을 것입니다. 무엇을 권하고 싶습니까?

+0

'중 .Close에 의해() 또는도록 SqlConnection을 배치 -

(. 자원 누수를 다루는 더 나은 전략이 있습니다.이 답변은 가비지 컬렉터가 실행 탐지에 적용 나는 완전히이 일에 대한 이유를 무시) "사용하기"에서 ** NO NO NO! ** .Close()는 그 자체만으로는 충분하지 않습니다. 이것이'using' 구조의 핵심입니다. 너무 많은 사람들은 .Close() _가 반드시 finally 블록 내에 있어야 함을 잊어 버립니다. –

답변

2

"가비지 컬렉터에 대해 생각해야한다면 틀린 일을하고있을 것입니다." (물론 다른 엄지 손가락이 있습니다 ...)

연결이 명시 적으로 또는 usingfinally 블록을 통해 닫히는 것을 확인하는 것이 가장 좋습니다.

분명히, 당신은 이미이 기술들을 이해하고 있습니다 ... 그래서 코드와 가능한 리펙터 만 있으면됩니다.

0

처분을 잊어 버리면 개체가 완성됩니다. 이러한 상황이 발생하는 시간을 제어 할 수있는 방법이 없으며 개체가 최종화되었는지 여부를 알 수있는 방법도 없습니다. 개체를 완성하기 위해서는 별도의 스레드를 만들어야하므로 응용 프로그램 속도가 느려집니다. 그래서 처분하고 싶습니다. IDisposable을 구현하는 프레임 워크의 모든 클래스에서 GC.SuppressFinalize에 대한 호출이 이루어 지므로 개체가 마무리되지 않습니다.

이 동작을 제어 할 수있는 방법은 없습니다. 개체를 더 이상 사용하지 않으면 자동으로 수집됩니다. 이것을 막기 위해 할 수있는 일은 GC.SuppressFinalize를 호출하는 것입니다.하지만 그걸 잊어 버리면 평생 망쳐 놓을 것이기 때문에 추천하지는 않을 것입니다.

항상 Dispose를 호출하는 몇 가지 간단한 메서드를 제공하는 코드에서 사용하는 래퍼 클래스 (자식 클래스 아님)를 만들 수 있습니다. 그렇지 않으면, 정말로 잘 확인하십시오.

+0

"보통 마무리 될 것"이라고 말하고 싶습니다. 정적 지속 시간에 첨부 된 객체를 'Dispose'하지 않으면 상황이 직접 또는 간접 참조 *가있는 객체가 가비지 수집 대상이되지 못하게됩니다. – supercat

4

SqlConnection은 봉인되었으므로이 인스턴스를 상속 할 수 없습니다. (그리고 나는 그렇게하는 것이 좋은 생각이라고 생각지 않는다. 가능한 경우 Dispose (false)로 코드를 추가해야하는데, 파이널 라이저가 호출하기 때문이다.

연결 처분을 잊어 버린 코드의 모든 위치를 감지 할 수있는 정적 코드 분석 도구를 사용하면 이러한 종류의 문제를 감지하는 것이 좋습니다. in Visual Studio에 내장 된 것이 있거나 FxCop을 사용할 수 있습니다. 이 프로젝트를 통해 분산되지 않도록

  • 가 한 층/조립/모듈에있는 모든 DB 연결 코드를 유지 :

    당신이 연결을 배치 잊지 않도록하기 위해, 그것은하는 것이 좋습니다.
  • SQL 명령을 수행하고 결과를 반환하는 유틸리티 메소드가 있습니다. 그래서 당신은 SQLConnection을 당신이 필요로하는 것보다 더 많은 장소를 만들지 않습니다.
  • C# using construct을 반드시 사용하십시오.
+2

+1 가장 좋은 방법은 근본 원인을 파악하고 연결을 끊는 것입니다. –

1

응용 프로그램에서 SQL 연결 풀링 (기본값)을 사용하는 경우 연결을 다시 사용하고 .Close()를 호출하거나 using() {} 블록을 닫을 때 닫히지 않으므로 문제가되지 않습니다. . 당신이 결코 알지 못할 것이기 때문에 GC가 컬렉션 개체를 재활용하도록 선택한 경우

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

는이 있다면, 그러나 그것은 문제가되지 것, 내가 GC 수집을위한 이벤트가 생각 해달라고, 귀하의 질문에 대답하려면 패스 (generational 알고리즘으로 인해 모든 객체가 정리되지는 않음).

나는 또한 타이머를 사용하려는 시도를 피할 것이고, "확인"을 할 것입니다. 아마도 당신이 그 객체에 대한 참조를 보유하고 그 객체가 삭제되는 것을 막을 수 있기 때문입니다.

+0

하지만 연결이 닫히지 않으면 즉시 다시 사용할 수 없으므로 연결이 풀로 반환되지 않으므로 문제가 발생합니다. 이로 인해 연결 풀이 소진되거나 중요한 자원을 소비하여 문제가 발생할 수 있습니다. –

+1

동의하지만 요점은 가비지 수집이 발생하는 시점을 OP가 알고 싶어한다는 것입니다. 내 요점은 SQL 연결 컬렉션 풀링 함께 발생합니다. 유일한 해결책은 실제로 GC 수정 이벤트 또는 타이머 확인에 의존하지 않고 .Close()가 호출되고 있는지 확인하고 수정하는 것입니다. – David

0

먼저 GC 사용을 고려 중이라면 어딘가에서 심각한 문제가 발생합니다. 코드 호출 닫기를 보장하는 가장 좋은 방법은 mocking과 같은 기술을 사용하여 코드를 단위 테스트하는 것입니다. 단위 테스트에서 닫기가 호출되었다고 표시하면 코드가 정확하며 가비지 수집기로 불필요하게 위험한 작업을 수행 할 필요가 없습니다.

둘째, 당신은 여전히 ​​런타임 체크 길을가는 주장하는 경우 것은 당신도 SqlConnectionStateChange 이벤트를 후킹되는 일을 고려해야합니다. 예를 들어, ConnectionState가 Open에서 Closed로 변경되면 실행됩니다.

1

가비지 수집기에 익숙하지 않고 정보를 얻을 수있는 직접적인 방법이 있는지 모르겠지만 첫 번째 아이디어는 다음과 같습니다.

더미 개체에 weak reference을 생성하기 만하면됩니다. 나중에 약한 참조를보고 객체가 더 이상 alive이 아니면 가비지 콜렉션이 발생했다고 가정 할 수 있습니다.

+0

그게 전부입니다. 최종 마무리를 막으려면 처분해야합니다. 약한 심판을 지키고 그것이 일어 났는지 확인하기 만하면 이미 너무 늦었습니다. (가비지 수집은 마무리 후 제공됩니다). –

+0

물론 가능합니다. 마지막 문장에서 언급 한 것처럼 "가비지 컬렉터가 호출되었는지 감지"라고 대답하고 싶었습니다.리소스를 누설하는 코드를 처음부터 작성하면 안됩니다. 정적 분석과 런타임 프로파일 링을 수행하면이 작업을 효과적으로 피할 수 있습니다. –