자바성능을 향상시키는 코딩

1. String보다는 StringBuffer가 빠릅니다.
예) String str = “aaa”;
    str = str + “bbb”;
    뭐 이런식으로….하거나 +=를 아시는 분은
    str += “bbb”; 하시죠.
문제점) 코드상으로는 str이라는 변수는 하나이지만 실제로는 “aaa”에 “bbb”라는
새로운 스트링객체가 생성되었기 때문에 이 두 개를 카피한 후 원래 스트링객체의 메모리
가 해제(Garbage Collection)되면서 새로운 str=”aaabbb”가 생깁니다.

해결책) StringBuffer의 경우 하나의 객체에 계속적으로 추가하는 식이 되므로 새로운
객체가 생성되지 않을 뿐더러, garbage collection할 필요가 없지요.

그러므로 StringBuffer sb = new StringBuffer();
         sb.append(“aaa”);
         sb.append(“bbb”);
로 코딩해야겠습니다.

2. 같은 기능이더라도 더 빠른 연산자가 있습니다.

(1)증감연산자가 가장 빠릅니다.
   예) int j = 1;
   j = j + 1;
  (j의 값을 1증가 시키려고 이렇게 코딩하는 사람은 많이 못봤지만…혹시나해서)
   이는 j++;로 코딩이 되어야 겠죠.

(2) +=을 사용하는게 빠릅니다.
  예)  a  = a + 10;보다는 a+=10;을 해주셔야겠죠.

(3) 곱셈나눗셈보다는 shift연산이 빠릅니다.
(shift를 하면 2를 곱하거나 나눌수 있지요)

3. 객체를 마구 만들지 않아야 겠습니다.
– 객체(String 포함)는 초기화되면 모두 힙이라는 메모리 영역에 할당이 됩니다.
객체를 마구잡이로 많이 만들면, 여기에 억세스 하는데 로드 및 이것이 해제될 때
Garbage Collection대상이 많아 진다는 점에서 불리합니다
-그래서 반복문안에서 String str = “xxx”;하거나 XXX x = new XXX()하면 얼마나
무리가 가는지 아시겠죠….지금이라도 혹시 while이나 for루프 안에 그런 코드가 들어
있지는 않은지 확인해보세요.
– 또한 인스턴스 변수는 클래스 초기화시 자동적으로 값(String이나 class는 null,
숫자는 0, boolean은 false)이 할당되므로 의도적으로 String var = null;할 필요가
없겠지요.
   
4. 변수도 범위와 타입에 따라서 성능이 다릅니다.
– 범위를 따지면 지역 메쏘드 변수가 스택영역에 저장되므로 가장 빠릅니다.
– 타입을 따지면 int와 참조 변수가 가장 빠릅니다. 혹시 int로 해도 될 것에
long으로 선언해서 쓰시는 분은 안계시죠? (본인이 그런 적이 있었지요…-.-;;)

5. 배열을 초기화에 따른 다른 특성을 잘 이해해야겠습니다.
– 다차원 배열로 정의할 경우 매번 생성자를 호출하기 때문에 꼭 필요한 경우가 아니면
다차원 배열로 정의하지 않아야겠습니다.
– 배열이 지역변수일 경우 메쏘드 호출 시 매번 초기화를 수행하므로, 배열을 static
으로 선언하면 초기화가 반복되는 것을 제거할 수 있습니다.
– 매번 메쏘드 호출 시 배열의 초기화가 필요할 경우, 한번 초기화된 배열을 카피해서
그 카피본을 사용하는 것이 더 빠릅니다.

6. 메소드도 자주 호출하면 부하가 걸립니다.
– 누가 자꾸 자기를 부르면 짜증나겠죠? 메소드를 부른다는 것은 그 메소드가 위치한
메모리를 참조한다는 의미입니다. 특히 자바는 객체지향언어이기 때문에 동적인메서드의
호출이 발생합니다. 즉, 메서드 오버로딩의 경우 정해진 메서드를 부르는게 아니라
그때 상황(메서드 인자, 리턴값)에 따라 판단해서 호출이 이뤄지므로 될 수 있으면 적게
부르는 방향으로 로직을 세워서 코딩을 해야겠습니다.
–  그래서 자주쓰는 메쏘드는 static으로 선언하고, 자주 참조하는 변수의 경우 final
등의 키워드를 사용하여 선언하면, 메모리에 고정이 되므로 성능을 높일 수가 있습니다.

7. 제어구조도 어떻게 하느냐에 따라 실행시간이 다릅니다.
– 즉, 군대에서 연병장을 뺑뺑이 돈다고 생각해보면 간단하죠. 몇바퀴를 돌리느냐, 단독
군장이냐, 완전군장이냐에 따라서 걸리는 시간이 틀리겠죠?
– 앞에서 지적했듯이 불필요한 메서드호출이나, 특히 객체생성은 자제해야겠습니다.
– 마찬가지로 로컬 메서드변수를 써서 카운팅을 해야겠죠. 혹시 인스턴스변수에 잡아두고
그 값을 증가시켜 카운팅하시는 분은 안계시겠죠?
– 배열의 바운드를 체크해야 할 경우, try-catch구문을 쓰시면 비교를 수행할 필요가
없기 때문에 실행시간이 줄어듭니다.
    
8. 적절한 버퍼를 사용하세요.
– 예전에 땅굴에 근무할 때 안에 샘물이 있는데 여기는 물이 한방울씩 똑똑 떨어집니다.
이것을 마시기 위해서 밑에서 입대고 있으면 성도 안차고 힘들겠죠. 뭐 당연한 원리지만
컵이나 주전자를 대놓고 물방울을 모아서 마시면 개운하듯이, 데이터를 읽어오거나 쓸 때
BufferedInputStream, BufferedOutputStream을 써서 버퍼링을 하면 오버헤드를 줄일
수 있습니다.
   
9. 동기화
– 동기화는 쓰레드가 하나의 자원을 놓고 싸우지 말고 락을 가진 쓰레드부터 차례로 그
자원을 쓰고 다음 쓰레드에게 락과 함께 자원을 반납하는 것이죠.
– 이때 주의할 점은 동기화를 안해도 되는 부분을 괜히 동기화하면 쓰레드가 하나밖에
수행되지 못하니까 잘 판단해야 한다는 것입니다.
– 동기화하는 방법은 메서드를 동기화하거나 블락을 동기화할 수 있는데 동기화된 메쏘드
를 호출하는 것이 동기화된 블록을 호출하는 것보다 약간 빠릅니다.
– 동기화된 메서드에서 동기화된 다른 메서드를 부를 경우에는 호출되는 메서드를
private 비동기화메서드로 바꾸면 모니터를 획득하는데 시간을 줄일 수 있겠습니다.

10. 동적바인딩과 동적클래스로딩
– 동적바인딩이란 프로그램 실행중 함수가 호출될 때 그 메모리 참조를 알아내는 것을
뜻합니다. 이는 메서드 오버로딩이나 오버라이딩 구현개념이죠. 즉, 메서드가 같은 이
름이라도 인자나 리턴값에 따라서 동적으로 호출되니, 호출될 때 그 메서드를 참조해야
하는 것이죠. 이때 메서드가 호출된 메모리참조를 알아내는 작업을 수행하는 시간이 약
간의 시간을 잡아 먹습니다. 그렇다고 메서드 오버로딩이나 오버라이딩을 안할 수는
없겠죠?

동적클래스로딩은 실행중인 클래스가 다른 클래스를 참조하였을 경우에 일어납니다.
이때 그 클래스를 직접 참조로 바꾸어 로딩을 하며, JVM에 의해 안전성을 검사가 이뤄진
후 클래스 초기화가 이뤄집니다. 이 역시 시간이 좀 걸리겠죠. 음….코드안에 마구
new해서 클래스의 인스턴스를 마구 만들어 대면 좋은 성능을 바라는 건 무리겠죠.