IT_Programming/Java

JAVA Tip & Tuning Technic

JJun ™ 2008. 9. 7. 23:31

튜닝이란 요청한 데이터 관련 작업을 처리하기 위해 최적의 I/O 처리 및 프로세스 처리 환경을
만들어 주는 것이라는 점을 명심하고 다음의 절차를 필수적으로 수행하기 바람. 참고로 개발단계에선
문제가 되지 않았지만 완료후 속도 문제가 대두되거나, 메모리, CPU 등의 누수가 발생되지 않도록
사전에 꼼꼼히 처리해야함. 즉, 개발하는 순간만이 아닌 서비스를 생각한 코딩이 선행되어야 함.

 

 

■ 튜닝이 필요한 경우

1.프로그램의 프로세스 과정이 복잡하여 수행 성능이 저하되는 경우
2.처리할 데이터가 매우 많아 성능이 저하되는 경우
3.특별한 원인없이 성능이 지속적으로 저하되는 경우
4.그 외 성능 저하의 문제가 지적되는 경우

 

 

■ 개발 필수 사항

1. 디스트 엑세스를 최대한 줄일 것.
2. 중복 검사를 위한 순환문 내의 프로세스 실행을 최소한으로 할 것.
   (중복 검사를 오버헤드가 적은 빠른 루틴으로 개선할 것.)


3. 과도한 객체 생성하면 죽여버림.
4. 메모리 낭비하는 거 있으면 죽여버림.(가비지 컬렉션을 줄여라)
5. 루프에서 똑같은 결과를 얻어내는 함수를 호출하거나 불필요한 new 하면 절대 안됨.
6. 불필요한 메소드 호출하면 안됨.
7. 객체를 재사용하자. 객체는 사용하기 전에 생성을 해야 하고, 사용이 끝난 뒤에는 가비지 컬럭션 처리를

   해주어야 한다. 그러므로 오버헤드를 줄이는 차원에서 궅이 객체를 다시 생성하지 않고 초기화하여
   재사용이 가능하다면 그렇게 하는 것이 좋으며, Static 메소드의 경우는 굳이 객체를 생성할 필요가 없다.


8. 쓸데없이 array 쓰면 겉멋들었다고 죽여버림.
    배열을 사용할 때 그 범위를 확인하기 때문에 순환문 내에서 배열을 이용하는 것은 임시 변수를 이용하는

    것보다 성능면에서 떨어진다. 배열은 순환문 밖에서 임수 변수에 값을 부여하는 것이 순환문에서 반복하여

    배열을 이용하는 것보다 좋다.  


9. Buffering은 아주 가끔 오래 끄는 메소드에서만 사용할것.

   그렇지 않으면 버퍼를 할당받는데 걸리는 시간이 더 걸림.

10. synchronized 블럭에서 함수 호출할때 졸라 주의할것. (데드락)
     다중 쓰레드 환경에서 경쟁 조건과 데드락(deadlock)은 피할 수 없는 관계이다.

     여러 개의 쓰레드가 동시에 동일한 변수, 객체 혹은 자원을 차지하려고 하는 경우 경쟁 조건이 발생하며

     경쟁 조건에서 한 쓰레드의 배타적 리소스 점유를 보장하는 방법으로 동기화를 사용하게 된다.

     동기화를 잘못 처리하는 경우 어느 쓰레드도 진행되지 못하는 교착 상태 즉, 데드락에 빠지게 되는데

     조금 복잡한 쓰레드 구조를 다루다 보면 종종 골머리를 앓게 되는 문제일 것이다.
     http://www.zdnet.co.kr/builder/dev/java/0,39031622,39130026,00.htm 참고할 것.


11. 동기화 할 수 있는 범위를 줄일 수 있는한 최대한 줄일 것. 동기화에 드는 오버헤드는

     쓰레드 프로그래밍 시 그 오버헤드가 크다.


12. synchronized는 잘만 생각해보면 그렇게 많이 하지 않아도 댐. 대부분 두려움에 의해서 하게 됨.
     프로그램의 흐름과 스레드간의 관계만 확실하게 알고 있다면 어느정도 안심하고 synchronized를

     대부분 하지 말 것.


13. String 대신 StringBuffer를 이용하자.
      '+' 연산자의 오버리딩을 통해 문자열을 붙여서 치환하면 편리하지만 객체의 연산은

      과도한 String 객체의 재생성을 유발.


14. Buffered 클래스를 잘 활용하자.
    스트림 처리를 위해 InputStream, OutputStream 대신 BufferedInputStream, BufferedOutputStream 을

    사용.


15. 서버에서 Vector나 Hashtable은 method자체가 모두 synchronized로 선언되어있음.
     MT에 문제가 없는 사용이라면 ArrayList와 HashMap을 사용할 것.


16. DB관련 객체를 철저히 관리할 것. 자바에서 사용한 DB자원이 언제나 자동으로 반환되지 않으므로 반드시

     DB자원을 반환. Connection, Statement 계열의 객체는 사용 후 반드시 닫아 준다.

     (특히, Statement 객체가 닫히면, 동일 계열의 ResultSet 또한 닫힌다.)


17. DB Connection Pool을 이용하자.

18. Thread Pool을 이용하자.

     (미리 여러개의 ready-to-run 쓰레드를 생성해 놓고, 어떤 작업에 사용하는 기술.)


19. Static 멤버(클래스 멤버)를 적절히 활용하자. 단 오용하면 오히려 메모리 낭비하게 됨.
     여타 인스턴스 멤버나 지역 변수들보다 접근이 더 느리고, 공용으로 사용되는 경우가 많을 경우 메모리에

     상주시켜 놓고 필요할 때마다 사용한다면 상당한 속도 향상을 가져올 수도 있다. 주의할 점은 너무 크기가

     큰 데이터를 static으로 선언하여 사용하는 것은 시스템 자원리 효율적 관리를 방해하며 쓸데없는 메모리

     낭비가 될 수 있다.

20. Try-catch 구문은 상황에 맞게 사용하자.
     Try-catch 구문은 예외처리를 위한 자바의 대표적인 구문이다.

     실제 로직상으로는 문제가 없지만 주변 상황에 따라 가변적인 변수들로 인해 오류가 발생 할 수 있는데,

     이를 처리하는 것이다. 하지만 이러한 Try-catch 구문을 사용할 때도 상황에 맞게 적절히 사용하면 오히려

     도움을 준다. 이는 오버헤드를 아주 작은 것으로 취급하기 때문이다.
     실제 if문을 써서 조건을 비교하는 코드보다 50%가량 빠르다. 만약 예외가 발생한다면, try-catch 구문의

     오버헤드가 약 3000배 이상 엄청나게 커지지만 예외가 자주 발생하는 부분이 아니라면 훨씬 효율적이다.

     그러나 Try-catch 구문도 순환문에서 반복 실행되면 그 오버헤드를 무시할 수 없으므로 순환문 내에서의

     사용은 피하는 것이 좋다.

     예) try {
            x = array[idx];  
          } catch (ArrayOutOfBoundsException e) {
            //error;
          }


21. 가급적이면 클래스 변수보다 stack 변수를 사용하라.
     클래스 변수는 접근할 때 stack 변수보다 훨씬 우회하여 접근하므로 stack 변수보다 더 느리다.

     stack변수는 일반적으로 정의해서 쓰는 변수들이며 인스턴스나 메소드 내에서 임시로 정의되고

     사용되다가 실행이 끝나면 자동으로 사라지는 변수이다.


22. 클래스를 통합하라.
     가급적 OOP의기본을 준수하여 클래스를 세분화시키는 것이 정석이지만 클래스 인스턴스 생성의 초기화

     오버헤드를 고려해 본다면, 합칠 수 있는 클래스는 통합하여 생성 오버헤드를 줄이는 것도 좋은 튜닝 기법

     이 될 수 있다. 또한 클래스를 jar형태로 묶어서 배포하는 것이 더 빠르다. 매번 디스크를 액세스 하지 않고

     한번에 전부 읽어 들이기 때문이다.

23. java.text.DateFormat 시리즈 애들은 call stack을 보면 알겠지만 메모리 잡아먹는데 Best of Best! 조심!
24. 정수의 크기를 비교할 때는 0과 비교하는 것이 가장 빠르다.
25. 순환문에서는 다른 타입보다 int를 쓰는 것이 훨씬 빠르다.
26. 더 빠른 속도를 보이는 연산자로 바꾸자.
     x=x+5 대신 x+=5

27. java.util.Date도 자주 생성하면 죽여버림
28. 개발중에는 사용하지 말도록 해야겠지만, 튜닝시에는 2의 거듭승들의 *와 / 연산은 모두 비트 연산하도록

     변경. (하지만, 잦은 호출이 아니면 튜닝시에도 할 필요 없음). 비트연산은 나같은 경우 서버에서는 거의

     사용하지 않음. 클라이언트 Imaging처리 할때 잦게 사용


29. 서버에서 유령사 용자 처리는 클라이언트의 일방적인 PING (Not ICMP but send dummy byte)을

     사용하도록 함.


30. 꼭 PING이 필요하다면, 추천하지는 않으나, ICMP를 구현하도록 함.
     절라 삽질해서 ansi c나 windows c로 짜논 JNI모듈이 있음. 필요하면 연락.


31. 아무리 튜닝이라고 하지만, 지금 튜닝하는 코드는 내일당장 상관이나 사장에 의하여 방향성의 변경이

     생길 수 있음을 숙지하고, Refactoring을 고려. (반드시 그래야함)

32. 서버에서 Vector같이 사용하는 아이가 있고, 이에 접근하는 빈도가 아주 크다면 List interface를 구현하지

     말고, 직접 구현할것. Object로 return되는 애들에 대한 Casting에 대한 귀찮음이 사라지고 Casting에

     의한 오버헤드가 줄어듬. (몸으로 느낀적은 없으나 책에서는 Casting도 재수없다고 말함)


33. 튜닝이 완료되었다고 생각하면, 일단 기뻐하고 그 후에는 Stress test를 반드시 한다.
     내가 보통 하는 테스트는 해당 Unit에 대해서 100만번 루프를 돌린다.