코드 보다보니까 어떤 사람은 싱글톤을 Lazy Initialization (지연초기화), Static Initialization (정적 초기화)로 나눠서 하니까 두개의 차이가 뭐가 있나 궁금해서 찾아보았다.
1. Lazy Initialization (지연초기화)
◈ 특징
- 인스턴스가 실제로 필요할 때까지 초기화를 미룸.
- 처음 접근할 때 인스턴스를 생성하므로 메모리를 효율적으로 사용할 수 있음.
- Lazy 클래스나 double-checked locking 등을 사용하여 구현할 수 있음.
- 초기화 순서와 타이밍을 명확하게 제어할 수 있음.
◈ 장점
1. 메모리 효율성 : 인스턴스를 실제로 필요할 때 까지 생성하지 않으므로 불필요한 메모리 사용을 방지함.
2. 초기화 제어 : 클래스가 로드 될 때가 아닌, 실제로 필요할 때 인스턴스를 생성하므로 초기화 시점을 제어할 수 있음.
3. Lazy<T> 사용시 간결한 코드 : .NET `Lazy<T>` 클래스를 사용하면 간결하고 안전하게 지연 초기화를 구현할 수 있음
◈ 단점
1. 약간의 성능 오버헤드 : Lazy클래스나 double-checked locking 구현 방식은 약간의 성능 오버헤드를 초래할 수 있음
1-1. Double checked locking : 락 획득, 메모리 배리어, 조건 체크로 인한 성능 오버헤드가 발생할 수 있음
1-2. Lazy<T> 클래스 : 내부 동기화, 추가 객체 생성, 함수 호출 오버헤드로 인해 약간의 성능 저하
※ 실제 영향 : 대부분의 애플리케이션에서는 이러한 오버헤드가 매우 미미하고 싱글톤 패턴의 이점이 오버헤드보다 훨 씬 더 큼
double-checked locking
double-checked locking은 초기화 시점에서의 스레드 충돌을 방지하기 위해 두 번의 체크를 수행하는 기법
처음에는 잠금 없이 인스턴스가 null인지 확인하고, null인 경우에만 동기화 블록을 사용해 인스턴스를 생성
2. 복잡성 : 일반적인 정적 초기화 방식보다 구현이 복잡 할 수 있음.
예제코드 - LazyInstance
public class Singleton
{
private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance
{
get { return lazyInstance.Value; }
}
private Singleton() { }
}
예제코드 - Double Checked Locking
public class Singleton
{
private static Singleton instance = null;
private static readonly object lockObj = new object();
// 생성자는 private으로 선언하여 외부에서 인스턴스 생성을 막음
private Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (lockObj)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
2. Static Initialization (정적 초기화)
◈ 특징
- 클래스가 처음 로드될 때 정적 초기화 블록에서 인스턴스를 생성함.
- 정적 필드 초기화 방식으로 구현
- JVM이나 .NET 런타임이 클래스 로드 시점에 스레드 안전성을 보장함.
- 애플리케이션 시작시 인스턴스가 생성되므로, 인스턴스가 항상 존재하는것이 보장됨
◈ 장점
- 단순성 : 구현이 간단하고 직관적
- 성능 : 초기화 과정에 추가적인 성능 오버헤드가 없음.
- 스레드 안전성 : 클래스 로드 시점에 초기화 되므로 스레드 안정성을 보장함
◈ 단점
- 초기 메모리 사용 : 클래스가 로드 될 때 인스턴스를 생성하므로 초기 메모리 사용이 많을 수 있음.
- 초기화 제어 어려움 : 클래스 로드 시점에 인스턴스가 생성되므로 초기화 시점을 제어하기 어려움
public class Singleton
{
private static readonly Singleton instance = new Singleton();
public static Singleton Instance
{
get { return instance; }
}
private Singleton() { }
}
◈ 비 교
특성 | Lazy Initialization | Static Initialization |
초기화 시점 | 인스턴스가 처음 필요할 때(즉, 첫번째 호출 시점) 리소스를 효율적으로 사용할 수 있고, 필요할때만 인스턴스 생성 |
클래스가 처음 로드될 때 (즉, 애플리케이션이 시작될때) |
메모리 효율성 | 필요할 때까지 인스턴스를 생성하지 않음 | 클래스 로드 시 인스턴스를 생성함 |
구현 복잡성 | 약간 더 복잡할 수 있음 | 구현이 간단하고 직관적임 |
성능 | 약간의 성능 오버헤드가 있을 수 있음 | 추가적인 성능 오버헤드 없음 |
초기화 제어 | 초기화 시점을 명확히 제어 가능 | 초기화 시점 제어 어려움 |
스레드 안전성 | Lazy<T>나 double-checked locking 사용 | 런타임이 스레드 안전성을 보장 |
'프로그래밍 > C#' 카테고리의 다른 글
[EntityFramework] DbContext 풀링 (0) | 2024.07.01 |
---|---|
[C#] Helper, Provider, Service, Manager 네이밍 관련 정리 (0) | 2024.06.25 |
-1을 uint에 넣어서 형변환을 하면 어떻게 될까? (0) | 2024.05.07 |
[디자인패턴]- State 패턴 (0) | 2023.03.14 |
[C#] DateTime값 Serialization/Deserialization시 DateTime.Minvalue 수치 변하는 현상. (0) | 2022.12.16 |
댓글