C# 이것저것/C# 기초

using문과 IDisposable을 이용한 리소스 해제

agingcurve 2025. 4. 7. 22:40
반응형

c#코드를 보면 심심찮게 using문을 볼 수 있다.

using (var connection = new SqlConnection(connectionString)) {
  ...
}

 

using문을 사용하면 변수의 범위를  using 코드 블록으로 지정하여 using 블록을 완료하면 자동으로 폐기한다.

 

이 예에서 SqlConnection 유형의 연결 변수는 using 문의 닫는 대괄호에 도달하면 가비지 수집 준비가 된 것으로 지정된다.

 

C#은 가비지 수집기가 있는 관리형 언어이기 때문에 가비지 수집기가 이를 대신 처리한다.

 

즉, C와 같은 비관리형 언어에서처럼 수동으로 메모리를 할당하고 할당 해제할 필요가 없다.

하지만 가비지 컬렉터가 혼동할 수 있는 경우 가비지 컬렉터에게 도움을 줄 수 도 있어야 된다

 

예를 들어, 가비지 컬렉터가 현재 코드 블록이나 변수 범위를 넘어 계속 유지해야 하는 경우 가비지 컬렉터가 언제 무언가를 수집할 수 있는지 어떻게 알 수 있을까?

 

 SQL 데이터베이스에 대한 연결이 있다고 가정할 때,

 

이 연결이 의도된 사용 사례를 넘어 ‘계속 유지’된다면 문제가 될 수 있다.

 

연결이 열려 있는 상태로 유지되어 동일한 데이터베이스에서

 

다른 코드가 실행되는 것을 차단하거나 버퍼 오버플로 해킹에 노출될 수 있는 문제가 발생할 수 있다.

 

이러한 메모리 누수를 방지하기 위해 “관리되지 않는” 리소스를 폐기한다.

 

이렇게 관리를 하지 않는다면, 리소스를 올바르게 폐기하는 것은 잊기 쉬운 일이다.

 

 SQL 데이터베이스에 대한 연결이 있다고 가정할 때.

 

이 연결이 의도된 사용 사례를 넘어 ‘계속 유지’된다면 문제가 될 수 있다.

 

연결이 열려 있는 상태로 유지되어 동일한 데이터베이스에서 다른 코드가

 

실행되는 것을 차단하거나 버퍼 오버플로 해킹에 노출될 수 있는 문제가 발생할 수 있다.

 

이러한 메모리 누수를 방지하기 위해 “관리되지 않는” 리소스 IDisposable 인터페이스를

 

구현하므로 관리되지 않는 리소스를 해제하려면 Dispose 메서드를 호출한다.

 

try - catch문으로 반환 분기가 여러개이면 어떨까?

 

이는 큰 코드 블록과 코드를 통과하는 여러개의 경로를 처리하며, 금방 혼란스러워질 수 있다.

 

using문은 이러한 try-finally 코드를 내부적으로 컴파일하여 블록으로 변환해준다.

 

try-finally는 오류 처리를 처리할 때 자주 사용하는 try-catch-finally 구조의 하위 집합이다.

 

코드를 try 코드 블록으로 감싼 다음 catch 코드 블록으로 감싸면 예외가 발생하면 

 

코드가 크래시되는 대신 catch 코드 블록에서 예외가 잡힌다.

 

마지막으로 catch 코드 블록 끝에 붙어 있는 선택적 코드 블록으로,

 

오류가 잡혔든 잡히지 않았든 코드 블록을 떠날 때 코드를 실행한다.

 

마지막으로 코드 블록에서 Dispose 메서드를 호출하면 결과나

 

오류 발생 여부에 관계없이 메서드가 실행된 후 항상 Dispose 메서드가 호출되도록 할 수 있다.

 

참고 ))

IDisposable을 구현하는 리소스에서 Dispose를 호출해도 즉시 가비지 컬렉션이 즉시 수행되지는 않는다. 단지 수거해도 안전하다는 플래그를 지정하고 다음 기회에 수거하도록 요청한다. 즉석 가비지 수집이 시작되지는 않지만 가비지 수집기가 결정하도록 하는 대신 리소스가 수집하기에 안전하다고 판단되는 시기를 관리한다.