String과 StringBuilder의 성능차이

 

위 사진 처럼 String을 계속해서 더해 400라인 정도의 쿼리를 만들었을때 733ms 의 실행시간이 걸렸고

 

 

StringBuilder를 사용해 똑같이 400라인의 쿼리를 만들었면 243ms의 실행시간이 걸린다.

3배라면 충분히 유의미한 차이라고 볼 수 있을 것이다.

 

 

같은 양의 쿼리를 생성하지만 이렇게 차이가 나는 이유가 무엇일까?

 

 

일단 본격적으로 String과 StringBuilder, StringBuffer의를 비교하기전에

간단하게 StringBuilder, StringBuffer의 차이를 집고 넘어가자면,

둘의 차이는 thread-safe한 클래스인가 아니냐의 차이이다.

 

StringBuffer 클래스가 스레드에 안전하게 설계되어 있어서 여러개의 스레드에서 접근해도 안전성을 보장한다.

더 자세한 차이는 이후에 다루겠다.

 

 

 

String vs StringBuilder vs StringBuffer

 

 

만약 위의 상황처럼 계속해서 String을 더해가야하는 상황이 발생하면 성능적으로 가장 우수한건 어떤 것일까?

 

일단 StringBuilder가 String보다 빠른건 눈으로 확인했다.

StringBuffer는 StringBuilder에서 스레드의 안전성을 더해주는 것이기 때문에 String보다는 빠르다.

 

StringBuilder와 StringBuffer중에서는 StringBuilder가 더 빠른데 그 이유는

StringBuffer가 스레드의 안전성을 보장하기 위한 작업이 진행되기 때문에 어느정도 차이가 나는 것이라고 이해하면 된다.

 

그런데 String과 StringBuilder, StringBuffer 사이에서 이렇게 유의미한 성능 차이가 나는 것일까?

 

이것은 String 객체가 호출될 때 마다 메모리에서 무슨 일이 진행되는지를 이해해야 한다.

 

 

String의 경우 과정이 진행 될 수록 주소값이 바뀌는 것을 확인 할 수 있다.

 

우리가 객체를 선언하면 메모리 Stack 영역에 주소값이 들어가고 실제 값은 Heap 영역에 저장된다.

주소가 계속해서 바뀐다는 것은 Heap 영역에 계속해서 새로운 객체를 생성하고 있다는 것이다.

 

즉, 과정이 반복될 수록 무의미한 String 객체를 Heap에 계속 생성하는 작업을 하기 때문에 성능이 낮아질 수 밖에 없다.

 

Heap 영역은 GC가 관할하는 구역이고, GC는 CPU를 많이 사용하기 때문에 무의미한 반복 수행을 통해

메모리 낭비와 응답속도에 차이를 보이는 것이다.

 

 

반면, StringBuilder와 StringBuffer는 새로운 객체를 생성하지 않고 기존에 있는 객체의 크기를 증가시키면서 값을 더하기 때문에 객체 생성 낭비가 없다.

 

 

 

마지막으로 StringBuilder와 StringBuffer에서 동기화 차이로 성능적인 차이가 발생하는 이유는

이후의 챕터 Synchronized 사용법에 대해 작성할 때 다뤄보겠다.

 

 

 

ref : 자바 성능 튜닝 이야기

 

+ Recent posts