본문 바로가기

C#

using 문법 +(UnityWebRequest)

using 문이란 C# 문법에서 메모리 사용을 효율적으로 관리할 수 있게 도와주는 구문 입니다.

 

리소스 자동 해제 (IDisposable)

using 블록을 사용하면, 객체 사용이 끝났을 때 자동으로 Dispose()가 호출되어 리소스가 해제됩니다.
주로 파일, DB 연결, 스트림 등 외부 리소스를 다룰 때 사용합니다.

 

using (var reader = new StreamReader("test.txt"))
{
    string line = reader.ReadLine();
    Console.WriteLine(line);
}
// 여기서 reader.Dispose()가 자동 호출됨 (파일 핸들 해제)

Dispose는 리소스를 사용하였을 때 해제를 하는 함수이다.

 

Dispose()를 해야 하는 이유는 외부 리소스를 안전하게 정리하기 위해서입니다. C#은 자동 메모리 관리를 해주는 가비지 컬렉터(GC)가 있지만, 가비지 컬렉터가 다루지 못하는 것들이 있습니다.

 

조금 더 자세하게 다뤄 보자면 

Dispose()를 해야 하는 이유

1. 관리되지 않는 리소스(Unmanaged Resources) 정리

  • 예: 파일 핸들, 데이터베이스 연결, 네트워크 소켓, 그래픽 리소스 등
  • 이런 리소스들은 가비지 컬렉터가 자동으로 해제하지 않음.
  • Dispose()를 호출해야 OS에 리소스 반환.
 

2. 리소스를 오래 붙잡고 있으면 문제 발생

  • 예를 들어, 파일을 Dispose()하지 않으면:
    • 다른 프로그램이나 코드가 그 파일을 열 수 없음.
    • "파일이 사용 중입니다" 오류 발생 가능.

3. 메모리 누수 및 성능 저하 방지

  • 관리되지 않는 리소스는 GC가 해제하지 않기 때문에, 메모리 누수(leak)가 생길 수 있음.
  • 리소스를 많이 열고 닫는 작업에서 Dispose() 안 하면 성능이 급격히 저하됨.

4. IDisposable 패턴으로 리소스 명확하게 정리 가능

  • IDisposable 인터페이스는 명시적으로 Dispose()를 호출하도록 만들어졌고,
  • using 문법을 통해 try-finally 없이 깔끔하게 처리 가능함.
 
class MyClass : IDisposable
{
    public void Dispose()
    {
          // 정리 작업 수행
    }
}
 
 
"Dispose()는 GC가 처리하지 못하는 외부 리소스를 명확히 정리하기 위한 방법이다."
 
 
그렇다면 using문으로 파일을 읽으면 어떻게 될까?
 
1. 파일 핸들 & 스트림은 운영체제 리소스
 
using (var reader = new StreamReader("test.txt"))
{
    var content = reader.ReadToEnd();
}

 

이 코드에서 일어나는 일:

  • StreamReader는 FileStream을 내부적으로 사용해서 파일을 엽니다.
  • 이때 *파일 핸들(파일을 가리키는 포인터 같은 것)이 열립니다. 이건 운영체제(OS)의 리소스!
  • ReadToEnd()로 읽은 텍스트 데이터는 메모리(RAM)에 로드됩니다.
  • 하지만 FileStream과 연결된 핸들은 명시적으로 닫아야 안전합니다.
    • 안 닫으면: 다른 코드/프로그램이 그 파일을 열 수 없을 수 있어요. "파일이 사용 중" 오류!

using은 자동으로 Dispose() 호출 → 파일 핸들 닫음

=> 그래서 더 이상 파일이 OS 리소스를 점유하지 않게 됨.

 

그럼 메모리는 어떻게 될까?

  • ReadToEnd()로 읽은 문자열 데이터는 여전히 메모리에 남아 있음.
  • 이건 C#의 가비지 컬렉터가 관리하는 "관리되는 메모리"이고, 이 데이터는 변수를 더 이상 사용하지 않으면 GC가 나중에 알아서 수거합니다.

리소스 종류                                어디에?                                              해제 방법

파일 핸들 OS 리소스 Dispose() 필요 (using으로 처리)
파일 내용(텍스트) 메모리(RAM, 관리됨) GC가 자동 수거

 

 

그럼 파일 스트림이란 뭔가?

파일 스트림(FileStream)이란?

파일에 데이터를 읽거나 쓰기 위해 운영체제와 연결된 통로(스트림)

 

조금 더 비유하자면:

  • 파일 = 물탱크
  • 파일 스트림 = 그 물탱크에 연결된 수도관
  • 데이터 = 물 (파일 안의 내용)

우리는 수도관(파일 스트림)을 통해 물탱크(파일)에서 물(데이터)을 꺼내오거나, 흘려보내는 거죠.

 

기술적으로 말하면?

  • FileStream은 .NET에서 제공하는 클래스입니다.
  • 이 클래스는 하드디스크에 있는 파일을 열고, 읽거나 쓰는 기능을 제공합니다.
  • 내부적으로는 OS에 파일 핸들(handle)을 요청해서 연결을 만듭니다.

FileStream fs = new FileStream("test.txt", FileMode.Open);

 

이 코드는: "test.txt"라는 파일을 열고 fs라는 스트림 객체를 통해 바이트 단위로 데이터를 읽거나 쓸 수 있게 해줍니다.

 

그럼 이러한 파일들을 왜 외부 리소스라고 부르는가?

 

외부 리소스 = .NET이나 CLR이 직접 관리하지 않는 리소스

  • 메모리는 .NET이 GC로 관리 → 내부 리소스 (managed)
  • 하지만 파일, 네트워크, DB 연결, 그래픽 핸들 등은 OS가 관리
    → 이건 외부 리소스 (unmanaged)

FileStream은 이 unmanaged 리소스를 다루는 "관리자 역할"을 하는 거예요.
그래서 다 쓰고 나면 Dispose()를 호출해서 OS에 "다 썼어요!"라고 알려야 합니다.

파일 스트림을 정리하자면

  • 파일을 읽고 쓰기 위한 클래스다.
  • 내부적으로 운영체제의 파일 핸들을 사용한다.
  • 그래서 외부 리소스이며, 사용 후 반드시 닫아야(Dispose) 한다.
  • 그 안에서 읽은 텍스트 내용은 메모리에 올라가며, GC가 나중에 정리한다.

Using 문을 정리하자면 

외부 리소스인 파일을 읽으려면 파일 스트림(FileStream) 을 통해 열어야 하고,

이 스트림은 운영체제(OS)의 자원(파일 핸들) 을 사용하기 때문에
다 사용한 뒤에는 꼭 닫아줘야 합니다. (Dispose() 사용 또는 using으로 (using문은 자동으로 Dispose가 내장되어 있음))

 

 

파일 스트림을 통해 읽어온 텍스트 데이터는 메모리(RAM) 에 올라가며,

이 데이터는 가비지 컬렉터(GC)가 자동으로 정리합니다.
따라서 따로 해제하지 않아도 되지만, 스트림은 반드시 명시적으로 닫아야 합니다.

 

 

+ 여기서 추가적인 정보를 더 붙이자면

FileStream하고 UnityWebRequest와의 차이를 조금 더 설명해보겠다.

 

FileStream은 OS 리소스를 직접 사용하는 파일 입출력 통로라서, 사용 후 반드시 Dispose로 닫아줘야 해. 반면 UnityWebRequest는 네트워크 통신을 Unity가 내부적으로 관리해주기 때문에, 반드시 Dispose할 필요는 없지만 자주 사용되거나 리소스를 아끼고 싶다면 using을 쓰는 것도 좋은 습관이다.

왜 UnityWebRequest에 using을 쓰는 게 좋을까?

Unity는 자동으로 리소스를 정리해준다

  • UnityWebRequest는 내부적으로 통신이 끝나면 Dispose()가 호출되도록 설계되어 있음
  • 그래서 간단한 요청에서는 굳이 신경 안 써도 돼

하지만 리소스 정리가 “언제” 되는지는 불명확함

  • Unity가 내부적으로 언제 Dispose()를 호출하는지 명확한 시점을 알 수 없음
  • GC 타이밍, MonoBehaviour의 생명 주기, 네트워크 상황 등에 따라 딜레이될 수 있음

그래서 문제가 생기는 경우는?

  • 게임 내에서 수십, 수백 번 요청을 날리는 경우
  • 이미지, 사운드, JSON 등을 연속적으로 여러 번 다운로드할 때
  • 모바일 기기처럼 리소스에 민감한 환경일 때

이런 상황에서 Dispose()가 늦게 되면:

  • 메모리 누수(memory leak) 처럼 보이는 현상 발생
  • 텍스처나 다운로드된 파일이 메모리에 계속 유지
  • 심하면 앱이 뻗거나, GC가 폭주해서 프레임 드랍 발생

그래서 using을 쓰는 이유는?

내가 직접 명확하게 리소스 해제를 컨트롤하기 위해서이다.

 

예)

using (UnityWebRequest req = UnityWebRequest.Get(url))
{
    yield return req.SendWebRequest();
    // 데이터를 사용
}
// 여기서 명확하게 req.Dispose() 실행됨 → 리소스 확실하게 해제

 

728x90

'C#' 카테고리의 다른 글

C# - Coroutine  (0) 2024.07.06
C# - 2  (0) 2024.05.19
C# - Custom Type2  (2) 2024.04.11
Virtual Table  (0) 2024.04.11
Class  (0) 2024.04.09