gimmesilver's blog

Agbird.egloos.com

포토로그



자바 프로그램 튜닝 프로그래밍

 요즘 개발하는 시스템 튜닝하는데 도움이 될까 싶어 '자바 성능을 결정짓는 코딩 습관과 튜닝 이야기' 라는 책을 사서 읽었습니다. 최적화라는 쉽지도 않고 흔하지도 않은 주제로 책을 쓴 저자의 노력과 용기에는 박수를 보내지만 내용면에서는 다소 실망입니다. 감수/추천평과는 달리 그닥 실용적이고 생생한 실전 노하우가 풍부하게 담겨있다고 말하기 힘들군요. 그저 수박 겉핥기정도?

 여러 가지 폭넓은 주제를 다루고 있지만 많은 부분에서 Thinking in Java 같은 입문 서적에서 이미 충분히 다루고 있는 내용을 반복적으로 언급하는데에 그치고 있습니다. 이를 테면 스레드 동기화 관련 내용을 다룬 9장에서는 단순히 Thread 클래스 및 synchronized 키워드 사용법 정도만 살짝 언급하고선 마지막에 synchronized 는 적당히 사용하지 않으면 성능이 저하돼요 그럼 다음 시간까지 안녕~ 뭐 이런 식입니다. 
 스레드 간 락 경쟁에 의한 대기 시간을 최소화 하기 위해선 락 블럭을 최소화하기 위해 매소드 선언부에 synchronized 를 두기 보다 딱 필요한 부분만큼만 synchronized 블럭을 이용한다거나 혹은 Atomic 객체를 사용하기, Collections.sysnchronized... 컬랙션보다는 java.util.concurrent 에서 제공하는 Concurrent... 관련 컬랙션을 사용해라 라든지, 좀 더 과감한 튜닝을 위해선 lock splitting 이나 lock striping 을 고려해보라든지 등등 정말 할 이야기가 많을 법도 한데 그냥 잘 사용하랍니다...이건 좀...

 그나마 이 책에서 괜찮은 부분은 여러 가지 프로파일링 툴을 소개하는 부분과 끝부분의 실전 사례 부분입니다. 이 마저도 없었으면 정말 돈주고 산거 후회할 뻔 했습니다. 차라리 자신없는 부분은 다 빼버리고 경험을 최대한 살려서 툴 사용법에 대해 좀 더 자세하게 설명하고 실전 사례나 풍부하게 담았으면 몇 배는 더 훌륭하고 전문성있는 책이 되지 않았을까 하는 생각도 해봅니다.
 암튼 원래 하고 싶은 이야기는 이게 아니고 이 책 5장에 보면 자바 컬랙션 객체들의 성능을 비교한 내용이 나옵니다. Set, List, Map 에 대해서 각 인터페이스의 구현물인 HashSet, TreeSet, LinkedHashSet, Vector, ArrayList, LinkedList, HashMap, HashTable, LinkedHashMap, TreeMap 성능을 측정하는데 다음과 같이 iteration을 사용하고 있습니다. 

HashSet<String> hs = new HashSet<String>();
TreeSet<String> ts = new TreeSet<String>();
LinkedHashSet<String> lhs = new LInkedHashSet<String>();

...

sw1.start();
Iterator<String> hsIter = hs.iterator();
while (hsIter.hasNext()) {
    String temp = hsIter.next();
}
sw1.stop();
sw2.start();
Iterator<String> tsIter = ts.iterator();
while (tsIter.hasNext()) {
    String temp = tsIter.next();
}
sw2.stop();
sw3.start();
Iterator<String> lhsIter = lhs.iterator();
while (lhsIter.hasNext()) {
    String temp = lhsIter.next();
}
sw3.stop();

그러나 이건 잘못된 방법입니다.
 List 는 그럴 수 있다쳐도 Set이나 Map같은 자료 구조의 주된 사용 목적은 전체 자료 순환이 아니라 검색입니다. 다른 분들은 과연 프로그램 내에서 Set이나 Map 객체 자료 전체를 순환하는 일이 얼마나 자주 있을지 모르겠지만 제 경우는 거의 없습니다. 어쨌든 중요한 것은 Set이나 Map 클래스 구현체들이 자료 순환보다는 검색에 적당하게 구현되었다는 점입니다. 그런 면에서 저런 식의 성능 평가는 의미가 없습니다.
 LinkedHashSet/Map 의 iteration 성능이 더 뛰어난 이유는 내부적으로 자료를 LinkedList 로 관리하기 때문입니다. 대신 자료 삽입/검색 시에는 LinkedList 관리를 위한 추가적인 작업 때문에 성능이 떨어집니다.
 따라서 책에서는 HashSet 이나 HashMap 보다 LinkedHashSet 이나 LinkedHashMap 의 성능이 더 좋다고 언급하지만 실제로 자료를 찾는 기능에 대해 성능을 측정하면 결과는 그 반대입니다. 썬에서 괜히 Set/Map 사용 시 일반적인 목적에서는 HashSet/Map 을 사용하라고 권고한 것이 아닙니다.

 하지만 이보다 더 중요한 점은 위에서 비교한 컬랙션 객체들이 단순히 성능 측정을 통해 어떤 것을 사용할 것인지 정하기에는 너무 다른 특성과 목적을 가지고 있다는 것입니다. 
 예를 들어 LinkedHashSet/Map 은 비록 일반적인 경우에는 HashSet/Map 보다 성능이 떨어지지만 LRU(Least Recently Used) cache 용도로 사용하기에 아주 적합합니다. 그래서 제 경우에는 빈번하게 참조하는 DB 결과물을 캐싱하는 용도로 LinkedHashMap을 사용합니다. 한편 TreeSet/Map 은 자료를 정렬해서 갖고 싶을 때 좋습니다.
 List 의 경우도 그렇습니다. 중간 삽입/삭제가 빈번하게 일어날 때는 LinkedList 가 좋지만 그렇지 않은 일반적인 경우에는 ArrayList 가 가장 무난합니다.
 이외에도 만약 불변 객체들을 관리하려는 목적이라면 HashMap 보다는 IdentityHashMap 을 사용하는 것도 고려해볼만 합니다. 객체 비교 시 equals() 대신에 == 연산자를 사용하기 때문에 더 빠릅니다(물론 아주아주 특수한 경우에만 해당합니다).
 하지만 이 책에서 HashTable과 Vector의 속도가 가장 좋게 나왔다고 해서 HashTable 이나 Vector 는 쓰지 마세요. 얘네들은 하위 호환성 때문에 어쩔 수 없이 남겨진 버림받은 존재입니다. 심지어 이들은 모든 메소드에 synchronized 처리가 되어 있기 때문에 책에 나온 측정 결과와는 달리 오히려 성능이 떨어집니다. 동기화가 필요없다면 이들을 쓸 이유가 전혀 없고 설령 동기화가 필요하더라도 Vector 대신 Collections.synchronizedList() 나 CopyOnWriteArrayList 를, HashTable 대신 ConcurrentHashMap 을 사용하는 것이 더 좋습니다.

핑백

  • gimmesilver's blog : ConcurrentHashMap vs. HashTable 2009-02-17 19:57:46 #

    ... 지난 번에 자바 프로그램 튜닝이라는 글에서 동기화된 Map이 필요하다면 HashTable 대신에 ConcurrentHashMap 을 사용하는 것이 더 좋다고 썼습니다만 그 이유에 대해서는 언급하지 않 ... more

  • ConcurrentHashMap vs. HashTable | StyleWear 2014-12-22 22:36:10 #

    ... 반응형 Jsp홈페이지 Apink+ StyleWear UN평화 서포터즈 취업캠프 창업 아카데미 Newspeed ConcurrentHashMap vs. HashTable 지난 번에 자바 프로그램 튜닝이라는 글에서 동기화된 Map이 필요하다면 HashTable 대신에 ConcurrentHashMap 을 사용하는 것이 더 좋다고 썼습니다만 그 이유에 대해서는 언급하지 않 ... more

덧글

  • 세라비 2009/01/03 17:17 # 삭제 답글

    제가 받은 인상과 정확하게 일치하네요. ㅎㅎㅎ
  • silverbird 2009/01/03 22:01 #

    아아 세라비님도 책 제목에 낚였었나 보군요...
  • 2009/01/03 20:19 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 이상민 2009/01/10 07:10 # 삭제 답글

    글 잘 읽었습니다.
    책 제목에 낚이셨다면 대단히 죄송합니다.

    참고로 툴에 대한 사용법은
    위의 이름에 링크된 블로그의 카테고리중 Tools --> Profiling 에 정리해 놓았습니다.
    감사합니다.
  • silverbird 2009/01/10 21:31 #

    책 쓰신 분이군요...사과를 받을 정도는 아닙니다. 맘 상하시지는 않으셨길 바랍니다.
  • truecolor 2009/03/28 00:35 # 삭제 답글

    뒤늦에 최근에 올린 글 링크를 타고 읽었습니다.

    "다른 분들은 과연 프로그램 내에서 Set이나 Map 객체 자료 전체를 순환하는 일이 얼마나 자주 있을지 모르겠지만 제 경우는 거의 없습니다"

    >> 저는 제가 만드는 프로그램에서 (게임이나 그런 거 아닙니다) 해쉬테이블이 가장 중요한 자료구조인데 또 가장 중요한 건 여기서 자료 전체 순회를 하는 것입니다. Set은 자바의 Set은 잘 모르겠지만 STL은 아시다시피 정렬이 되어있기 때문에 전체 순회도 당연히 매우 큰 의미가 있습니다.
  • silverbird 2009/03/30 09:18 #

    전체 순회가 의미가 없다는 것이 아닙니다. 순회가 성능에 영향을 미칠 정도로 자주 사용되는가 하는 문제입니다.
댓글 입력 영역