내가 기고한 어떤 글에 어느 분께서 질문을 올려서 여기에 정리한다.
질문의 골자는 "다른분께서 Perm 영역에서는 GC 가 발생 안한다고 했는데, Perm영역에서도 GC발생한다는 것이 이상하다"는 내용이다. 
나도 내 눈으로 확인하기 전까지는  GC가 발생안한다고 생각했으므로 당연한 질문이라고 생각한다.
지금까지 내가 무슨 이야기하는지 이해가 안되시는 분은
이글 (http://helloworld.naver.com/helloworld/1329) 먼저 읽으시면 조금 이해가 쉬울 것이다. 

다음의 소스를 보자.

public class InternTest {

  public static void main(String[] args) throws Exception{

    InternTest test=new InternTest();

    Thread.sleep(10000);   System.out.println("Starting");

    while(true) {

      test.callIntern();Thread.sleep(5000);

      System.out.print(".");

    }

  }

  private void callIntern() {

    for(int loop=0;loop<10000;loop++) {

      String a="1234567890"+System.nanoTime();

      String newString=a.intern();

    }

  }

}

 아주 간단한 소스인데, callIntern() 이라는 메소드를 보면 새로운 String을 계속 만들어 intern() 메소드를 호출하고 있다. 
이 클래스를 컴파일하고 jstat으로 모니터링하면 다음과 같은 결과를 볼 수 있다.
(jstat에 대해서는 "자바 성능을 결정짓는 코딩 습관과 튜닝 이야기"를 참조하거나,
http://helloworld.naver.com/helloworld/6043 를 참고하기 바란다.)

예를 들어 이 프로그램의 프로세스 ID가 4800 일 때 결과는 다음과 같이 출력된다.  

$ ./jstat -gcutil  4800 3s
  S0   S1   E     O    P     YGC  YGCT  FGC FGCT  GCT
  0.00 0.16 10.43 8.79 
98.37 3869 1.247 87  1.815 3.061
  0.02 0.00 52.12 8.77 
45.21 3884 1.250 88  1.840 3.090
  0.00 0.16 83.39 8.77 
98.89 3903 1.257 88  1.840 3.097
  0.00 0.16 27.11 8.78 
15.04 3919 1.262 89  1.857 3.119

 
P라고 표시되어 있는 내용의 값이 계속 변경되는 것을 볼 수 있다.
여기서 P가  Perm 영역의 사용량(%)인데, 보는 것과 같이 그 크기가 지속적으로 바뀌는 것을 볼 수 있다.
그리고 우측에 있는 FGC라는 값도 증가하는 것이 보인다.

자바의 Perm 영역에 클래스와 메소드 정보만 저장되어 있다고 생각하는 것이 일반적이지만,
실제로는 intern된 String 값도 이 영역에 저장된다. 

참고) intern된 String은 뭘까?
String은 기본적으로 equals()메소드로 값을 비교한다. 그렇게 되면 char값들을 비교하기 때문에 성능이 느릴 수 있지만, String 의 실제 값에 대해서 intern() 메소드를 호출하면 해당 값은 equals() 메소드가 아닌 == 으로 비교가 가능하다. 추가로 이  intern()메소드는 native 메소드로 선언되어 있다. 
하지만, 이렇게 String비교를 조금 빠르게 하기 위해서 intern() 메소드를 호출한 후 결과를 비교하는 것은 Perm영역을 마구잡이로 사용하겠다는 의미이기 때문에 "절대" 권장하는 방법은 아니다. 그냥 이런 것이 있구나 정도로 참고하고 있기 바란다. ^^;

추가로,
Perm영역에 어떤 데이터들이 저장되어 있는지 보려면 
jmap -permstat pid
명령어로 확인하면 되며,
그 결과에 가장 첫 출력물을 보면 interned String 크기가 출력된다.


2013.8.5 추가
와 
(의 댓글)에 따르면 JDK 7 이상 부터는 String.intern() 메소드의 호출 결과가 더 이상 Perm 영역에 들어가지 않고 Heap 영역으로 들어가게 되었네요. ^^;


 


Posted by tuning-java
,