유호진 [ finecool@lycos.co.kr ] 님께서 JAVA자바동호회 게시판에 올리신 글 내용입니다.
퍼온글입니다. (from javaservice.net)
아시는 내용이겠지만 다시 한번 되새겨 보자는 의미에서..
안녕하세요. 絶對高手입니다.
자바를 코딩하면서 본인도 모르게 자바의 성능이 저하시키는 코딩을 하는 경우가 많습니다.
그래서 어제 새벽내내 인터넷을 돌아다니면서 어떻게 하면 자바의 성능을 더 향상할 수 있
는지 조사했지요. 음...벌써 새벽 4시군요... -.- 어제는 새벽4시까지 술로 지새웠는데
오늘은 그래도 보람된 꺼리로 밤을 새는군요.
각설하고 자 그러면 어떻게 하면 좀더 빠르고 효율적인 코딩을 할 수 있는지 알아봅시다.
그리고 아래의 두 가지문제에 대해서 생각을 해보시길 바랍니다. 물론 저도 고민하고 있
습니다. 지금 jsp + JavaBeans로 구성된 프로젝트를 하고 있습니다. 기술회의를 하다가
이런 문제가 제기되었습니다.
1. Beans 객체에서 데이터를 쿼리해올 때 어떤 것이 더 빠른 성능을 낼 것인가에 대해
논란이 있었습니다. 즉 엔터티빈에 해당하는 클래스를 만들어서 그것을 벡터에 집어 넣고
서 화면에 뿌려줄 것인가, 아니면 String 배열을 선언하여 거기에 데이터를 집어넣고
이것을 화면에 뿌려줄 것인가.
2. 빈즈클래스를 상속하여 메서드를 부르는 게 나은지 그냥 new해서 그 클래스의 메서드
를 호출하는 게 좋은지 서로간에 이견이 있었습니다.
이글을 읽어 보시고 어느 것이 더 나을지 판단해보시길 바랍니다.
자 그럼 자바 코딩을 할 때 어떤 것이 더욱 나은 성능을 가져오는 코딩인지 잘못된 예와
이유, 개선방안을 살펴보도록 하죠.
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해서 클래스의 인스턴스를 마구 만들어 대면 좋은 성능을 바라는 건 무리겠죠.
자바도 파고들면 그리 쉬운 언어가 아닌것 같네요...쩝...
모두들 열심히 하시길 바라면서, 잘못된 부분이 있으면 리플 부탁드립니다.
그리고 처음에 저희가 고민한 2가지 문제에 대한 의견도 같이 부탁해요.
※주의: 이글은 충남대학교 컴퓨터과학과 김영국(ykim@cs.chungnam.ac.kr)님이
인터넷상에 올린 글을 참조로하여 썼음을 분명히 알려드립니다. | |