[C#] Singleton 패턴 잘못 쓰면 발생하는 문제 – 메모리 누수 & DI 문제
[C#] Singleton 패턴 잘못 쓰면 발생하는 문제 – 메모리 누수 & DI 문제
C#에서 Singleton 패턴은 전역 인스턴스를 하나만 유지한다는 점에서 자주 사용됩니다.
하지만 잘못된 싱글톤 사용은 메모리 누수, 테스트 어려움, 의존성 주입(DI) 충돌 등의 문제를 발생시킬 수 있습니다.
이 글에서는 Singleton 패턴의 기본 구조와 함께 실무에서 문제가 되는 사용 예, 그리고 올바른 구현 방법을 소개하겠습니다.
✅ Singleton 패턴 기본 구조
// 기본 싱글톤 구현 (Lazy + Thread-safe)
public sealed class MyService
{
private static readonly Lazy<MyService> instance =
new Lazy<MyService>(() => new MyService());
public static MyService Instance => instance.Value;
private MyService()
{
// 생성자
}
public void DoSomething()
{
Console.WriteLine("작업 실행");
}
}
이 구조는 실무에서 가장 많이 쓰이는 Lazy + Thread-safe 패턴입니다.
하지만 아래와 같은 문제들을 유발할 수 있습니다.
⚠️ 문제 1 – 테스트 코드 작성 어려움
싱글톤 인스턴스는 전역 상태를 가지기 때문에, 단위 테스트에서 격리(Isolation)된 테스트 작성이 어렵습니다.
Mocking이 어렵고, 테스트 간 상태 공유로 인해 예기치 않은 결과가 발생할 수 있습니다.
// 다음 테스트는 상태 공유 문제를 일으킬 수 있음
MyService.Instance.DoSomething(); // 이전 테스트의 상태가 남아있음
⚠️ 문제 2 – DI(Dependency Injection)와 충돌
최근에는 의존성 주입(Dependency Injection)을 활용하는 경우가 많은데, 이 때 Singleton 패턴은 DI 컨테이너가 객체 생명주기를 관리하는 방식과 충돌할 수 있습니다.
// DI Container에서 관리되는 객체 예시
services.AddSingleton<IMyService, MyService>();
DI 컨테이너를 사용한다면 굳이 수동으로 Singleton 패턴을 구현할 필요 없이
컨테이너에게 Singleton
생명주기를 맡기는 게 더 안전하고 유연합니다.
⚠️ 문제 3 – 메모리 누수
GC(가비지 컬렉터)는 더 이상 참조되지 않는 객체를 정리하지만, Singleton은 앱 종료 시까지 메모리에 유지되기 때문에 불필요한 리소스가 계속 메모리에 남아 메모리 누수처럼 보일 수 있습니다.
// 싱글톤 내부에서 IDisposable 리소스를 직접 관리하면 누수 위험
private SqlConnection conn = new SqlConnection(...);
→ 이럴 땐 IDisposable을 구현하지 말고, 외부에서 의존성 주입 받는 구조로 개선해야 합니다.
✅ 해결 방법 – DI와 함께 쓰는 Singleton
.NET Core 이상에서는 Microsoft.Extensions.DependencyInjection
을 통해
싱글톤 생명주기를 컨트롤 할 수 있습니다.
// Startup.cs 또는 Program.cs에서 등록
services.AddSingleton<IMyService, MyService>();
// 생성자 주입으로 사용
public class MyController
{
private readonly IMyService myService;
public MyController(IMyService myService)
{
this.myService = myService;
}
}
이처럼 DI Container를 활용한 Singleton 등록 방식이 테스트 코드 작성, 생명주기 관리, 메모리 안정성 측면에서 훨씬 유리합니다.
🧠 마무리 요약
- 전통적인 Singleton 패턴은 간단하지만 테스트/확장/DI 측면에서 단점이 많음
- 의존성 주입을 활용해 Singleton을 안전하게 구현하는 것이 권장됨
- 싱글톤 내부에 리소스를 직접 소유하지 말고, 외부에서 주입받는 구조가 이상적
실무에서는 항상 유지보수성과 테스트 가능성을 고려한 구조 설계가 중요합니다.
이 글이 도움이 되셨다면 공감/댓글 부탁드려요 😊