어제 성능 테스트를 하다가 성능이 안나오는 프로그램이 있어 확인을 하던 중, 
어떤 프로그램에서 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()가 계속 발생할 수가 있는지를 확인해 볼 수 있다. 

Posted by tuning-java
,