출처 : 책 자바 성능 튜닝이야기 -'왜 자꾸 String을 쓰지 말라는거야' 편

 

이 책에 나온 초보 개발자 나초보는 서비스를 개발하고 나서 보니 GC가 많이 발생된단 사실을 알게 되었고

성능을 올리기 위해 GC에 영향을 끼치고 있던 String 부분을 개선해보기로 하였다. 

 

문제를 일으키던 부분은

String a = "test"; / for문을 통해 a += "XXX";

이런식으로 String에다 계속 값을 더하는 부분이었다.

String을 이렇게 사용하면 성능 적인 부분에서 문제를 일으킬 수 있다.

 

for문이 100,1000번 이상 돌아간다 가정해보면 메모리 사용률이 올라가고, 응답속도는 낮아질 것이다. 

 

그렇다면 어떻게 해야 할까?

  • StringBuffer 클래스와 StringBuilder 클래스를 사용하여야 한다. 
    • append() 메서드를 활용

 

StringBuffer 클래스와 StringBuilder 클래스의 차이는 

StringBuffer 클래스는 스레드에 안전하게 설계되어 있으므로 여러 개의 스레드에서 하나의 StringBuffer객체를 처리해도 전혀 문제가 되지 않는다. 반면 StringBuilder 클래스는 단일 스레드에서의 안정성만을 보장한다. 

 

String a = new String();
StringBuffer b = new StringBuffer();
StringBuilder c = new StringBuilder();

for(int loop = 0 ; loop < 10000; loop++) {
	a += "abcde";
}

for(int loop = 0 ; loop < 10000; loop++) {
	b.append("abcde");
}
String tempB = b.toString();

for(int loop = 0 ; loop < 10000; loop++) {
	c.append("abcde");
}
String tempC = c.toString();

이런 소스가 실행된다면 결과가 어떻게 될까? 어느 것이 가장 빠르고 메모리를 적게 사용할까? 

 

  응답시간 생성된 임시 객체수 메모리 사용량
a (String) 95초 4,000,000 약 95Gb
tempB (StringBuffer) 0.24초 1400 약 37.5Mb
tempC (StringBuilder) 0.17초 1400 약 37.5Mb

그렇다, 응답시간과 메모리 사용량에서 엄청난 차이가 보인다

응답시간과 메모리 사용량에서 가장 좋은 성능을 보인건 StringBuilder이다. 

 

왜 이럴까?

새로이 더해진 문자열은 새로운 주소를 갖는 객체가 생성이 되기 때문이다. 

a에 "abcde"를 더하면 새로운 String클래스의 객체가 만들어지고, 이전에 있던 a객체는 필요 없는 쓰레기 값이 되어 GC대상이 된다. 이러한 작업이 반복 수행되면서 메모리를 많이 사용하게 되고, 응답 속도에도 많은 영향을 미치게 된다. GC를 하면 할수록 시스템의 CPU를 사용하게 되고 시간도 많이 소요된다. 그래서 프로그래밍을 할 때 메모리 사용을 최소화하는 것은 당연한 일이다. 

 

Wrap-up

  • String은 짧은 문자열을 더할 경우 사용한다.
  • StringBuffer는 스레드에 안전한 프로그램이 필요할 때나, 개발 중인 시스템의 부분이 스레드에 안전한지 모를 경우 사용하면 좋다. (클래스에 static으로 선언한 문자열을 변경하거나, singleton으로 선언된 클래스에 선언된 문자)
  • StringBuilder는 스레드에 안전한지의 여부와 전혀 관계 없는 프로그램을 개발할 때 사용하면 좋다. 메서드 내에 변수를 선언하는 경우가 이에 해당되겠다.
  • WAS나 시스템이 JDK5.0 이상을 사용한다면, 컴파일러에서 자동으로 StringBuilder로 변환해 주긴 한다. 하지만 반복 루프를 사용해서 문자열을 더할 때는 객체를 계속 추가한다는 사실에 변함이 없으므로 StringBuilder, StringBuffer사용을 권장한다. 

 

+ Recent posts