어제 성능 테스트를 하다가 성능이 안나오는 프로그램이 있어 확인을 하던 중,
어떤 프로그램에서 System.gc()라는 불러서는 안되는 코드를 부른 다는 것을 직감(?)했다.
개발된 코드를 뒤져도 그 코드는 안나오고,
어디를 뒤져오 안나오길래 아주 단순한(?) 방법으로 원인이 되는 놈을 찾아 내었다.
(여기서 단순한 방법은 http://www.tuning-java.com/421 를 참고하시길...)
우선 관련해서 DirectByteBuffer를 막 생성하면 안된다고 이야기해 주신 정보를 제공해주신 훌륭한 "응주박" 선수에게 감사하다는 말을 전한다.
이러한 문제가 발생하는 원인을 확인해 보기 위해서 아침에 출근하자마자 샘플 코드를 작성해봤다. 먼저 다음의 코드를 보자.
import java.nio.ByteBuffer;
public class DirectByteBufferCheck {
public static void main(String[] args) {
DirectByteBufferCheck check=new DirectByteBufferCheck();
for(int loop=1;loop<99999999;loop++) {
check.getDirectByteBuffer();
if(loop%100==0) System.out.println(loop);
}
}
public ByteBuffer getDirectByteBuffer() {
ByteBuffer buffer;
buffer = ByteBuffer.allocateDirect(65536);
return buffer;
}
}
뭐 별거 없다.
루프 돌면서 ByteBuffer의 allocateDirect() 메소드를 호출해서 DirectByteBuffer를 생성한다.
이 프로그램 돌리고 GC 상태를 보면 다음과 같이 나온다.
$ jstat -gcutil 1484 1s
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 2.00 0.90 22.04 0 0.000 77 0.736 0.736
0.00 0.00 0.00 0.90 22.07 0 0.000 84 0.795 0.795
0.00 0.00 0.00 0.90 22.07 0 0.000 91 0.855 0.855
0.00 0.00 0.00 0.90 22.08 0 0.000 97 0.911 0.911
0.00 0.00 0.00 0.90 22.08 0 0.000 104 0.975 0.975
0.00 0.00 0.00 0.90 22.08 0 0.000 111 1.041 1.041
0.00 0.00 0.00 0.90 22.08 0 0.000 117 1.093 1.093
빨간색으로 표시한 Full GC 횟수가 1초에도 무지막지하게 증가하는 것을 볼 수 있다.
왜 이런 현상이 발생할까?
그 원인은 ByteBuffer.allocateDirect(65536) 메소드 호출 부분에 있다.
이 메소드를 부르면
1. DirectByteBuffer라는 클래스의 생성자가 호출되고
2. 그 생성자에서는 Bits.reserveMemory(65536) 이라는 static 메소드를 호출한다.
Bits 클래스의 소스는 "요기링크"를 참조하기 바란다.
링크를 보면 왜 DirectByteBuffer클래스의 객체를 계속 생성하면 System.gc()가 계속 발생할 수가 있는지를 확인해 볼 수 있다.
'Java > Java Advanced' 카테고리의 다른 글
High Performance Libraries of Java (0) | 2012.04.06 |
---|---|
[Java Spec] JVM Spec과 Java Language Spec 문서 업데이트 (0) | 2011.09.01 |
[자바 메모리 모니터링] JVM에서 사용하는 전체 메모리를 모니터링하는 방법 (0) | 2011.07.21 |
[LogCompilation] 자바의 JIT가 어떻게 컴파일이 되는지 보고 싶다면... (0) | 2011.05.03 |
[Advanced Java] Attach API (0) | 2011.03.28 |