String, StringBuffer, StringBuilder 비교

1 분 소요

자바에서 문자열을 다룰때 String이 아닌 StringBuilder 나 StringBuffer를 사용하는 것이 성능에 유리하다.

참고로 StringBuffer나 StringBuilder 가 제공하는 메서드는 동일하다.
둘의 차이는 StringBuffer가 ThreadSafe 하게 설계되어있다는 차이가 있다. 따라서 만약 멀티쓰레드 환경에서 사용되는 클래스라면 내부에서 StringBuilder보다는 StringBuffer 를 사용하는것이 안전하다.

1. 성능 차이 비교

자바 성능 튜닝 이야기 책에서 테스트된 내용을 보면 String 백만번 더하는 연산에 대해서 측정된 시간차이는 아래와 같다.

사용한 Class 주요 소스 응답 시간
String a += value 95초
StringBuffer a.append(value) 0.24초
StringBuilder a.append(value) 0.17초

2. 성능 차이 발생 이유

String 으로 더하는 연산을 할 경우 새로운 객체 생성 및 GC 연산이 엄청나게 발생한다. abcd 라는 값을 계속 더한다고 가정하면 아래와 같다.

 String result = new String();
 String value = "abcd";
 
 for(int i=0; i<100; i++) {
 	result += value;
 }

이 코드가 수행되면, 반복문이 하나씩 돌때마다 새로운 String 객체가 생성되고 다음 반복문이 돌때 이전에 생성된 객체는 GC 대상이 된다.

호출에 따른 객체 생성과 GC 대상은 다음과 같다.

호출 순서 객체 생성 GC 대상
1 “abcd” 없음
2 “abcdabcd” “abcd”
3 “abcdabcdabcd” “abcdabcd”

이렇게 반복문을 돌수록 메모리 사용이 늘어나고, GC도 자주 발생하여 응답속도가 현저하게 떨어진다.

StringBuffer, StringBuilder는 String과 달리 반복문을 돌아도 새로운 객체를 생성하지 않는다.

대신 이미 생성된 StringBuffer, StringBuilder 객체의 크기를 증가시킨다. 새로운 객체 생성이 없기 때문에 메모리 사용에 효율적이고 GC발생이 없어 응답속도가 비교적 빠르다.

3. 결론

  1. 문자열 연산에서 String은 짧은 문자열을 더하는 경우에만 사용한다.

  2. 문자열 연산이 멀티쓰레드 환경에서 동작할 수 있다면 StringBuffer를 사용한다.

  3. 특히나 멀티쓰레드 환경인데 Class가 Singleton이거나 클래스 내에 static으로 선언된 문자열을 수정한다면 StringBuffer를 사용해야 한다. (잘못하면 호출 순서에 따라서 값이 예상하지 못한 방향으로 수정되버릴 수 있다)

  4. ThreadSafe와 무관한 환경이거나 메서드 내부에서 변수를 선언한 형태라면 StringBuilder를 사용하면 된다. (StringBuffer보다 속도가 더 빠르기 때문에)

4. 참고

4.1. 버전에 따른 차이

JDK 5.0 에서부터는 문자열 더하는 과정이 있을때 컴파일로가 알아서 StringBuilder로 변환해준다.

String str = "Hello" + "World" + "Haha" + 3;

컴파일된 이후 디컴파일 해보면 아래와 같다.

String str = (new StringBuilder("Hello")).append("World").append("Haha").append(3).toString();

하지만 반복문을 통한 문자열 연산은 여전히 새로운 String 객체가 생성되는 방식이기 때문에 주의해야 한다.

4.2. CharSequence

CharSequence는 인터페이스로 이 인터페이스를 구현한 클래스로는 CharBuffer, String, StringBuffer, StringBuilder 가 있다.

개발할때 문자열을 파라미터로 받는것이 있다면 CharSequence를 받는것이 성능상 좋겠다.
그러면 파라미터를 넘기는 곳에서 문자열 생성으로 어떤것을 사용하든 다 넘길 수 있다.

만약 파라미터로 String을 받게 하면 문자열 생성에 사용한 Class에 ㄸ라서 toString()을 해야하고 무의미하게 하나의 객체를 추가적으로 생성해야 하기 때문에 메모리 효율이 떨어진다.

카테고리:

업데이트:

댓글남기기