본문 바로가기
Program Language/C#

Part1. C# 첫발 내딛기(25. String과 StringBuilder의 차이)

by 토담이아빠 2023. 1. 20.

String과 StringBuilder의 차이

 

C#에서 String을 이용하여 문자열 합성을 하다 보면 간혹 느려질 때가 있습니다. 이유는 '+' 연산 때문입니다. 이 연산자를 사용하면 사용할수록 문자열을 더할 때마다 새로운 메모리 생성과 복사가 일어나기 때문입니다. 이번 장에서는 string의 이러한 단점을 해결해 주는 StringBuilder에 대해서 정리해 보았습니다.


String의 문자열 합성 속도


String 변수에 100만 개의 문자열을 더하는 연산(+)을 한다고 가정해 봅시다. 그러면 String은 100만 개의 문자열을 저장하는 메모리를 할당하고 더할 때마다 생성되는 99만 9999개의 문자열을 저장하는 메모리리를 생성합니다. 그리고 매번 복사가 일어납니다. c#에서는 가비지 콜렉터라는 기능이 있어 이런 메모리는 자동으로 처리해 주지만 그전까지는 계속 유지되어 실행속도를 느리게 합니다.

이런 현상은 다음 예제를 통해 확인할 수 있습니다. string 변수에 실제로 100만 개의 문자열을 더하는 작업은 너무 오래 걸리므로 10만 개로 테스트해서 최종 시간을 체크해 보도록 하겠습니다.


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StringFormat_exam
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string str = "The numbers are: ";

            Stopwatch time = new Stopwatch();
            time.Start();
            for(int i = 0; i < 100000; i++)
            {
                str += i.ToString();
            }
            time.Stop();

            Console.WriteLine($"String Sum: {time.ElapsedMilliseconds}ms ");
            
        }
    }
}

결과

String Sum: 8480ms

PC 성능에 따라 틀리겠지만 현재 사용하고 있는 PC로는 10만개의 문자열을 합성하는 데 8초가 넘게 걸렸습니다. 처음엔 원래 이 정도 걸리는 게 아닌가 하고 그냥 넘길 수 있지만 다음의 StringBuilder의 문자열 합성속도를 보면 생각이 달라집니다.

StringBuilder의 문자열 합성 속도


StringBuilder는 이런 String의 문자열 합성 시 나타나는 단점을 보완한 클래스입니다. StringBuilder로 선언한 변수의 문자열이 변경될 때에는 자동으로 필요 메모리를 계산하고 조정합니다. 이것은 실행속도면에서 엄청난 이득을 가져다줍니다. 다음의 예제는 StringBuilder의 문자열 합성속도입니다. String과 동일하게 10만 번 합성합니다.


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StringFormat_exam
{
    internal class Program
    {
        static void Main(string[] args)
        {
            StringBuilder str = new StringBuilder();
            str.Append("The numbers are: ");
            Stopwatch time = new Stopwatch();
            time.Start();
            for(int i = 0; i < 100000; i++)
            {
                str.Append(i.ToString());
            }
            time.Stop();

            Console.WriteLine($"String Sum: {time.ElapsedMilliseconds}ms ");
            
        }
    }
}

결과

String Sum: 8ms

동일 조건에서 문자열을 10만 번 합성하는데 String은 8초가 걸린 반면 8ms가 걸렸습니다. StringBuilder가 약 1000배나 빠르다는 것입니다. 물론 합성 개수가 적으면 그 차이는 미비할 수 있습니다. 하지만 위 예제처럼 합성이 누적될수록 그 차이는 매우 크게 납니다.

이처럼 문자열 자주 변경되는 합성일 경우 String보다는 StringBuilder사용을 권장합니다. 추가적으로 StringBuilder의 속성과 메서드에 대해서 정리했습니다.


속성 동작
Capacity StringBuilder 객체에 할당된 메모리가 허용하는 최대 문자수를 가져오거나 설정합니다.
Length StringBuilder 객체의 길이를 가져오거나 설정합니다.
메서드 동작
Append StringBuilder 객체의 끝에 문자열을 추가합니다.
Clear StringBuilder 객체의 모든 문자들을 없애줍니다.
CopyTo string의 일부분을 문자 배열로 복사합니다.
EnsureCapacity StringBuilder 객체의 용량을 최소한 지정된 값이 되도록 합니다.
Equals 이 객체가 다른 객체와 같은 지를 부울값으로 리턴합니다.
Insert 특정한 위치에 지정한 문자열을 삽입합니다.
Remove 특정 위치에 있는 문자열을 삭제합니다.
Replace StringBuilder r객체에서 문자 혹은 Substring을 다른 문자 혹은 substring으로 대체합니다.
ToString StringBuilder 객체의 값을 String으로 변환합니다.

참고
"초보자를 위한 C# 200제(2판)" / 저자 : 강병익

댓글