스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록

2024.07.09 TIL - StringBuilder, List 메모리 단편화

테크러너 2024. 7. 9.

메모리 단편화란?

메모리 단편화는 메모리 관리 시스템에서 가용 메모리 블록들이 작고 불규칙하게 분산되어 있는 상태를 의미한다. 이로 인해 메모리를 효율적으로 사용할 수 없게 되어 성능 저하가 발생할 수 있다.

 

메모리 단편화는 크게 두 가지 유형으로 나눌 수 있다.

 

1. 내부 단편화 (Internal Fragmentation)

고정 크기의 메모리 블록을 할당할 때, 요청된 메모리보다 큰 블록이 할당되어 사용되지 않는 잔여 공간이 발생하는 경우이다. 이 잔여 공간이 바로 내부 단편화다.

예를 들어, 64바이트의 메모리 블록을 할당했는데 실제로 필요한 메모리는 50바이트라면, 나머지 14바이트는 낭비된다.

 

2. 외부 단편화 (External Fragmentation)

가변 크기의 메모리 블록을 할당할 때, 메모리 해제가 반복되면서 작은 크기의 자유 메모리 블록들이 여기저기 흩어져 있어 큰 메모리 블록을 할당할 수 없는 상황을 말한다.

예를 들어, 100바이트의 연속된 메모리를 할당하려고 하지만 30바이트, 20바이트, 50바이트의 작은 자유 메모리 블록들이 여기저기 분산되어 있어 100바이트를 연속적으로 할당할 수 없는 경우를 말한다.

 

 

C#에서 문자열(String) 메모리 단편화

문자열의 생성, 수정, 삭제 과정에서 메모리가 효율적으로 관리되지 않아 단편화가 발생할 수 있다.

문자열은 불변(immutable) 객체로, 한 번 생성되면 수정할 수 없기 때문에 문자열 조작 시 새로운 문자열 객체가 계속해서 생성된다. 이는 메모리 할당과 해제를 빈번하게 일으켜 단편화를 유발할 수 있다.

 

메모리 단편화 발생 상황

문자열을 연결할 때마다 새로운 문자열 객체가 생성된다.

예를 들어, `string result = str1 + str2 + str3;`와 같이 문자열을 여러 번 연결하면 중간 단계에서 많은 임시 문자열 객체가 생성되고, 이들이 메모리에 할당된다.

이러한 임시 객체들은 가비지 컬렉터에 의해 나중에 해제되지만 반복적인 할당과 해제가 단편화를 초래할 수 있다.

 

단편화 완화 방법

1. StringBuilder 사용

`StringBuilder`는 가변 문자열 객체로 문자열을 수정할 때마다 새로운 객체를 생성하지 않고, 내부 버퍼를 사용하여 효율적으로 문자열을 조작한다.

예를 들어, 아래와 같이 사용하면 메모리 할당과 해제를 최소화하여 단편화를 줄일 수 있다.

StringBuilder sb = new StringBuilder(); 
sb.Append(str1); 
sb.Append(str2);

 

2. 문자열 보간 및 Format

문자열 보간과 `string.Format`을 사용하여 불필요한 문자열 연결을 줄일 수 있다.

string result = $"{str1} {str2} {str3}";
string result = string.Format("{0} {1} {2}", str1, str2, str3);

 

단편화 완화에 가장 효과적인 방법은?

문자열 보간 및 Fomat은 새로운 문자열 객체를 생성한다. 이로 인해 많은 임시 객체가 생성되고, 가비지 컬렉터가 이를 처리해야 하므로 메모리 단편화가 발생할 수 있다.

작은 문자열을 합칠 때는 괜찮지만 큰 문자열을 자주 합치거나 많은 조작을 할 때는 비효율적이다.

반면 `StringBuilder`는 반복적인 문자열 조작 시 중간에 임시 객체를 생성하지 않으므로 단편화 완화에 가장 효과적인 방법이다.

 

List<T>에서의 메모리 단편화

`List<T>`는 내부적으로 배열을 사용하여 요소를 저장하며, 요소가 추가될 때 배열의 크기가 부족하면 더 큰 배열을 할당하고 기존 요소를 새로운 배열로 복사한다. 이 과정에서 메모리 단편화가 발생할 수 있다.

 

메모리 단편화 원인

1. 크기 확장

`List<T>`는 초기 용량을 정하지 않으면 기본적으로 작은 크기의 배열로 시작한다. 요소가 추가되면서 배열의 용량을 초과할 경우 새로운 더 큰 배열이 할당되고, 기존 배열의 요소들이 복사된다. 이 과정에서 사용되지 않는 메모리가 남게 되어 단편화가 발생할 수 있다.

 

2. 요소 제거

`List<T>`에서 요소를 제거하면 내부 배열의 크기는 그대로 유지되므로 비어 있는 공간이 생긴다. 이 공간을 재사용하지 않으면 메모리 단편화가 발생할 수 있다.

 

단편화 최소화를 위한 방법

1. 초기 용량 설정

`List<T>`를 생성할 때 예상되는 최대 용량을 설정하여 초기 크기를 지정하면, 확장 과정에서 발생하는 단편화를 줄일 수 있다.

List<int> myList = new List<int>(1000);

 

2. TrimExcess 메서드 사용

`TrimExcess` 메서드를 사용하여 `List<T>`의 용량을 실제 요소 수에 맞게 줄일 수 있다. 이 방법은 요소를 많이 제거한 후에 유용하다.

myList.TrimExcess();

 

3. Capacity 속성 사용

`Capacity` 속성을 사용하여 `List<T>`의 용량을 조정할 수 있다. 필요할 때 용량을 늘리거나 줄이는 데 사용할 수 있다.

myList.Capacity = myList.Count;
반응형

댓글