C#에서 String, StringBuilder, StringBuffer 클래스는 문자열을 다룬다는 공통점이 있습니다.
하지만 문자열을 연산하는 과정에서 성능속도 차이가 다르므로 차이점을 알아보도록 하겠습니다.
String vs StringBuilder, StringBuffer
String 클래스는 불가변적(immutable)이고 StringBuilder와 StringBuffer는 가변적(mutable)입니다.
예제를 활용해 더 자세히 알아보자면,
// 문자열 객체 생성
String str_1 = "hello";
String str_2 = new String(" world!");
위처럼 C#에서는 String 객체를 2가지 방법으로 생성할 수 있습니다.
str_1처럼 문자 리터럴(literal), 즉 큰 따옴표("")를 사용하거나 str_2처럼 new 연산자를 사용하는 것입니다.
문자 리터럴(literal)로 생성하면 먼저 String Pool에 같은 값이 있는지 확인하고
있으면 해당 주소값을 할당, 없으면 새로운 객체를 만들어 String Pool에 할당하고 그 주소값을 리턴합니다.
만약, str_2처럼 new 연산자로 String 객체를 생성하면 내용이 같더라도 강제로 힙(heap) 영역에 생성하고 그 주소값을 리턴합니다.
위처럼 2가지 방법으로 String 클래스의 참조변수인 str_1, str_2를 생성했을 경우에
// 문자열 객체 생성
String str_1 = "hello";
String str_2 = new String(" world!");
str_1 = str_1 + str_2; // hello world!
str_1이 가르키는 영역의 값이 str_1과 str_2 문자열을 합쳐 "hello word!"로 변경되었다고 생각할 수 있지만, 실제로는 "hello word!"라는 값을 가지는 새로운 힙 메모리 영역이 생성되고 str_1에는 그 곳을 가리키는 주소를 저장하게 됩니다.
그리고 "hello"가 저장되어있는 영역은 가비지(Garbage)로 남아있다가 C#의 특징 중 하나인 가비지 컬렉션(Garbage Collection)에 의해 필요없게 된 영역을 해제시키게 됩니다.
위처럼 String 클래스는 불가변적(immutable) 특성을 가지기 때문에 문자열이 빈번하게 변경되는 경우,
힙 메모리에 많은 가비지(Garbage)가 생성되어 힙 메모리 부족으로 성능이 저하될 수 있습니다.
그래서 위처럼 문자열이 빈번하게 변경되는 경우 사용하는 문자열 클래스가
StringBuilder, StringBuffer 입니다.
StringBuilder와 StringBuffer는 가변적(mutable)이라는 특징처럼 말 그대로 문자열 연산이 발생하면 기존의 버퍼 크기를 늘리게됩니다. 따라서 문자열의 추가, 수정, 삭제가 빈번하게 발생하는 경우라면 StringBuilder와 StringBuffer를 사용하는것이 효율적입니다.
StringBuilder sb_1 = new StringBuilder("hello");
sb_1.append(" world!"); // hello world!
StringBuffer sb_2 = new StringBuffer("hello");
sb_2.append(" world!"); // hello world!
StringBuilder와 StringBuffer의 차이
StringBuilder와 StringBuffer의 차이점으로는 synchronized(동기화) 키워드 지원여부가 있습니다.
StringBuilder는 synchronized(동기화) 키워드를 지원하지 않기 때문에, 단일쓰레드 환경에서 안전하고, StringBuffer는 synchronized(동기화) 키워드를 지원하여 멀티쓰레드 환경에서 안전하다는 점입니다.
String | StringBuffer | StringBuilder | |
가변여부 | 불가변적(immutable) | 가변적(mutable) | 가변적(mutable) |
Thread Safe | o | o | x |
사용 예 | 문자열 연산 적고, 멀티쓰레드 환경 | 문자열 연산 많고, 멀티쓰레드 환경 | 문자열 연산 많고, 단일쓰레드 환경 |