자동 가비지 수집을 피하는 방법

반응형

1. 값 타입과 참조 타입 차이점 이해하기

.NET에는 값 타입과 참조 타입 두 가지 데이터 타입이 있다. 이 두 타입의 차이점은 궁극적으로 데이터를 저장하는 방법에 있다. 값 타입의 인스턴스는 자체적으로 데이터를 보유하는 반면 참조 타입의 인스턴스는 데이터의 메모리 위치에 대한 참조를 보유한다. 값 타입은 null일 수 없으며 이를 포함하는 객체가 존재하는 한 존재한다. 따라서 값 타입은 최악의 경우 가비지 수집에 미치는 영향이 미미한다. 실제로 값 타입은 GC의 힙 내에 존재하지 않는 경우가 많다.

 

적절한 경우 값 타입을 사용하여 GC 할당을 방지하고 GC 수집 속도를 더 빠르게 만들 수 있다.

 

 

 

2. 클래스 대신 구조체 고려

타입, 특히 배열이나 일반 컬렉션에서 사용할 타입을 만들 때 구조체로 만드는 것이 좋다. GC 컬렉션이 실행되면 참조 타입만 확인하여 여전히 도달 가능한지 확인한다.

 

이것은 개별 구조체 인스턴스에 대한 작은 이점일 뿐이지만 배열을 사용하면 이점이 빠르게 증가한다. 구조체 배열을 사용하면 GC는 배열 자체가 여전히 활성 객체 인지 확인한다. 그러나 구조체에는 몇 가지 단점이 있으므로 너무 빠져들면 안된다.

 

그럼에도 불구하고 수천 개의 인스턴스가 생성되거나 객체 풀을 생성하는 것이 실용적이지 않은 데이터 구조가 있는 경우 구조체는 GC 성능 및 자동 GC 수집 최소화 측면에서 큰 이점이 얻을 수 있다. .

 

 

 

3. 인스턴스를 재사용할 수 있도록 클래스를 디자인한 다음 적절한 경우 개체 풀을 사용한다.

플랫폼에 관계없이 배열 및 일반 컬렉션을 제외한 대부분의 관리 개체는 크기가 작은 경향이 있으므로 개체를 다시 만드는 대신 재사용하는 것이 유용한 트릭이 될 수 있다. 이렇게 하면 GC의 내부 할당 카운터가 증가하지 않아 자동 GC 수집이 실행되지 않는다.

 

여러 번 사용할 가능성이 있는 객체를 작성하여 생성자의 각 오버로드에 해당 객체를 다시 초기화하기 위해 호출할 수 있는 동등한 공용 메서드가 있도록 한다. 그런 다음 리스트와 같은 일반 컬렉션 유형을 사용하여 객체 인스턴스를 풀링한다.

 

시간이 중요한 코드에서 GC 컬렉션을 제거할 수 없는 경우 객체 풀이 매우 비쌀 수 있다는 점에 유의하자.

 

 

 

4. 컬렉션 타입에 대해 초기 용량을 사용하는 컬렉션 생성자 오버로드를 사용한다.

내부적으로 List<T>, Dictionary<TKey, TValue> 및 기타 제네릭 컬렉션은 추적 변수와 함께 하나 이상의 배열을 사용하여 유효한 데이터를 보유하는 내부 배열 항목 수를 식별한다. 컬렉션에 항목을 추가하면 내부 배열의 용량을 초과할 때마다 새 배열(이전 용량의 두 배)이 생성되어 GC의 내부 할당 카운터가 증가한다.

 

해당 컬렉션에 한 번에 몇 개의 요소가 있는지 대략적으로 알고 있는 경우 생성자 오버로드 중 하나를 사용하여 특정 초기 크기로 내부 배열을 만들 수 있다. 초기 용량을 충분히 높게 설정했다고 가정하면 내부 배열의 크기를 조정할 필요가 없으므로 새 할당 생성을 피할 수 있다.

 

 

 

5. 할당을 생성하는 일반적인 작업에 유의한다.

.NET에는 명확하지 않은 방식으로 GC 할당을 생성하는 몇 가지 일반적인 작업이 있다. 두 가지 주요 대상은 값 타입의 박싱과 대부분의 문자열 연산이다.

 

박싱은 값 타입을 인터페이스에 명시적으로 캐스팅할 때 발생한다. 인터페이스를 인스턴스화할 수는 없지만 CLR은 인터페이스 인스턴스를 만들 때마다 인터페이스를 참조 형식으로 처리한다. 참조 타입 컨테이너('박스')는 Object 또는 인터페이스로 캐스트될 때 기본 값 타입을 보유하기 위해 작성되어야 한다. 복싱에 대해 알면 코드의 메모리 의미를 더 잘 알 수 있다 .

 

문자열은 .NET에서 이상한 것이다. 이들은 참조 타입이므로 GC에서 관리하지만 저장 방식으로 인해 변경할 수 없고 재사용할 수 없다. 따라서 문자열 변환과 관련된 거의 모든 작업은 어떤 식으로든 GC 할당을 초래한다.

 

문자열 작업으로 인한 할당을 최소화하는 한 가지 방법은 System.Text.StringBuilder를 사용하는 것이다. 안타깝게도 .NET에서 문자열을 사용하는 클래스 중 StringBuilder를 사용하는 클래스는 많지 않다. 그럼에도 불구하고 StringBuilder를 사용하여 여러 부분에서 문자열을 구성하고 StringBuilder 인스턴스를 재사용하여 할당량을 줄일 수 있다.

반응형