본문 바로가기
C#

[C#] BCL string과 StringBuilder의 차이점

by Jcoder 2020. 11. 29.

string과(8초) StringBuilder(0초) 실행 결과

string 타입은 불변 객체(immutable object)이기 때문에 string에 대한 모든 변환은 새로운 메모리 할당을 하게된다.

예를 들어 string.ToLower() 메소드를 보자.

 

string txt = "Hello World";

string lwrTxt = txt.ToLower();

 

txt 변수는 힙에 있는 "Hello World"를 가리킨다. 그 상태에서 ToLower()를 호출하면 원문이 통째로 복사된 다음에 그것이 소문자로 변경되어 반환된다.

 

불변 타입의 string 클래스가 발생시키는 가장 큰 문제는 문자열을 더할 때다. 아래 코드를 실행 결과 8초가 걸렸다.

 

// string

1. 힙(heap)에 "Hello World" 문자열을 담은 공간을 할당.

2. 스택에 있는 txt 변수에 할당된 힙의 주소를 저장.

3. txt + "1" 동작을 수행하기 휘애 txt.Length + "1".Length에 해당하는 크기의 메모리를 힙에 할당, 그 메모리에 txt 변수가 가리키는 힙의 문자열과 "1" 문자열을 복사.

4. 다시 스택에 있는 txt변수에 새로 할당된 힙의 주소 저장.

5. 30만번 반복.

 

30만번을 끊임없이 메모리 할당하고 이전의 문자열을 다시 복사하는 과정이 걸리기 떄문에 8초가 걸렸다.

 

// StringBuilder

1. StringBuilder는 내부적으로 일정한 양의 메모리를 미리 할당한다.

2. Append 메서드를 통해 들어온 인자를 미리 할당한 메모리에 복사.

3. 2번 과정을 30만번 반복, Append로 추가된 문자열이 미리 할당한 메모리보다 많아지면 새롭게 여유분의 메모리를 할당.

 

즉, 잦은 메모리 할당과 복사가 없여졌기 때문에 성능 향상이 되었다.

 

// 메모리 할당

개체의 기본 용량은 StringBuilder 16 문자이 고, 기본 최대 용량은 Int32.MaxValue 입니다. 이러한 기본값은 및 생성자를 호출 하는 경우에 사용 됩니다

MSDN 참고 : StringBuilder 클래스 (System.Text) | Microsoft Docs

 

StringBuilder 클래스 (System.Text)

변경할 수 있는 문자열을 나타냅니다.Represents a mutable string of characters. 이 클래스는 상속될 수 없습니다.This class cannot be inherited.

docs.microsoft.com

 

 

static void Main(string[] args)

{

    Console.WriteLine("string과 StringBuilder");

    // string

    string txt = "Hello World"; // 1, 2

 

    System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();

    stopwatch.Start();

    // 30만번 반복

    for (int i = 0; i < 300000; i++) // 5

    {

    txt += "1"; // 3, 4

    }

    stopwatch.Stop();

 

    Console.WriteLine($"string ms : {stopwatch.ElapsedMilliseconds}, second : {stopwatch.ElapsedTicks/ System.Diagnostics.Stopwatch.Frequency}");

 

   // StringBuilder   

    System.Text.StringBuilder sb = new System.Text.StringBuilder(); // 1

 

    string txt1 = "Hello World";

    sb.Append(txt1);

    stopwatch.Reset();

    stopwatch.Start();

    for (int i = 0; i < 300000; i++) // 3

    {

    sb.Append("1"); // 2

    }

    stopwatch.Stop();

 

    Console.WriteLine($"StringBuilder ms : {stopwatch.ElapsedMilliseconds}, second : {stopwatch.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency}");

}