'JAVA'에 해당되는 글 51건
- 2008.12.31 Java HotSpot VM 기술자료 요약정리 2
2008. 12. 31. 11:51
Java HotSpot VM 기술자료 요약정리
2008. 12. 31. 11:51 in JAVA
문서의 목적
이 문서의 목적은 Java 로 작성된 프로그램을 오랜 기간동안 수행하면서 발생할 수 있는 기술적 이슈에 대응하는데 필요한 기본 지식을 정리하는데 있다.
모든 내용을 정리하기 보다는 필요한 내용만을 선별해서 요약한다.
HotSpot VM 기본
JDK 1.2 부터 HotSpot VM 이 제공됐다.
Java HotSpot VM 은 "Hot" 메소드를 선택적으로 컴파일해서 성능을 높이는 기술을 채택한 VM 이다.
Client VM 과 Server VM 으로 나뉘며, Client VM 은 초기 시작시간, 총 사용 메모리에 중점을 두고, Server VM 은 전체적인 실행속도에 중점을 둔다.
Client VM 과 Server VM 은 기본적인 런타임 코드는 공유하며, HotSpot 영역을 컴파일하는 컴파일러만 다르다.
Client VM 과 Server VM 은 다음과 같은 조건에 의해 선택된다.
- Server VM
- 물리적 CPU 가 2개 이상이고, 물리적 메모리가 2GB 이상이거나,
- -server 옵션을 명시적으로 사용했을 때
- Client VM
- 물리적 CPU 와 물리적 메모리 요건이 Server VM 기준을 만족못하거나,
- -client 옵션을 명시적으로 사용했을 때
Lager Heap Size
Solaris 의 경우 Solaris 9 과 JDK 1.4.1 이상을 쓴다면 MPSS (Multiple Page Size Support) 기능을 지원받아서 Virtual Memory 이용효율을 높일 수 있다. MPSS 를 이용하지 못하는 경우에는 ISM 기능을 쓸 수 있다.
Linux 와 Windows 의 경우는 http://java.sun.com/javase/technologies/hotspot/largememory.jsp 를 참조해서 설정할 수 있다.
64bit JVM 을 이용하면 보다 넓은 Heap 공간을 쓸 수 있다. 이 글을 쓰는 시점에서 6.0 버전에 대해 64bit JVM 이 제공되는 OS 는 다음과 같다.
- Solaris (Sparc, x86, x64)
- Linux (x86, x64)
- Windows (x86, x64)
- AIX (ppc)
- HP (Integrity, PA-RISC,
Heap Generations
Java HotSpot VM 은 3개의 Generation 으로 Heap 을 구성하는데, Young, Old, Permanent 가 그것이다. 3가지로 구분하는 것은 각 Generation 별로 최적의 GC algorithm 을 적용하는 것이 더 효과적이기 때문이다.
Young Generation
- Young Generation 에는 최초로 인스턴스가 생성되는 Eden 영역과 Eden 에서 살아남은 인스턴스들이 잠시 거쳐가는 From 과 To 영역이 있다. From 과 To 에서는 오래 유지되거나 너무 큰 인스턴스는 Old Generation 으로 옮겨진다. Eden 에서도 크기가 너무 큰 인스턴스의 경우 바로 Old Generation 으로 옮겨지기도 한다.
Old Generation
- Old Generation 에는 오래 유지되는 인스턴스가 저장된다.
Permanent Generation
- 클래스, 메소드 등의 데이터가 인스턴스 형태로 저장된다.
Garbage Collector
상황에 따라 다음의 선택사항들중 하나가 선택된다.
- Serial vs Parallel
- Concurrent vs Stop-the-world
- Compacting vs Non-compacting vs Copying
Serial Collector
- Server 급이 아닌 환경에서 자동으로 선택된다. 명시적으로 지정하려면 -XX:+UseSerialGC 옵션을 이용한다. 클라이언트에서는 대부분의 경우 적합한 Collector 이다.
- Young Generation
- GC 될 때 Eden 에서 Garbage Collection 되지 않고 살아남은 인스턴스는 Surivvor Space 인 To 로 옮겨진다. To 에 충분한 공간이 없을 경우에는 바로 Old Generation 으로 옮겨진다. From 에서도 Gargabe Collection 이 연이어 일어나며, 여기에서 살아남은 인스턴스는 Surivvor Space 인 To 로 옮겨진다. 만약, 인스턴스의 생성시기가 기준에 비추어 오래되었거나 To 에 충분한 공간이 없을 경우에는 바로 Old Generation 으로 옮겨진다. Garbage Collection 이 끝나면 From 과 To 의 역할이 서로 바뀐다.
- Old Generation and Permanent Generation
- 쓰이고 있는 인스턴스들을 Mark 한 다음, Mark 되지 않은 Garbage 들을 청소하고, 인스턴스들을 Compaction 하는 처리가 이루어진다.
Parallel Collector
- CPU 가 2개 이상이고, 물리 메모리가 많은 Server 급 환경에서 자동으로 선택된다. 명시적으로 지정하려면 -XX:+UseParallelGC 옵션을 이용한다. GC 시간이 약간 길어도 별로 상관이 없는 실행환경에 적합하다.
- Young Generation
- Serial Collector 와 동일한 algorithm 으로 Gargabe Collection 이 일어나며, 동시에 2개 이상의 프로세서가 있을 때의 잇점을 이용한다.
- Old Generation and Permanent Generation
- Serial Collector 와 동일하다.
Parallel Compacting Collector
- CPU 가 2개 이상이고, 물리 메모리가 많은 Server 급 환경에서 GC 시간이 너무 길지 않아야 하는 실행환경에 적합하다. 명시적으로 지정하려면 -XX:+UseParallelOldGC 옵션을 이용한다.
- Young Generation
- Parallel Collector 와 동일하다.
- Old Generation and Permanent Generation
- Parallel Collector 를 쓸 때 Garbase Collection 이 일어나면 3가지 상태로 진행된다.
- 첫 번째 상태는 marking phase 로 Application 실행을 잠시 멈추고, Application 에서 바로 접근가능한 인스턴스부터 시작해서 여러 스레드들에 의해 각각의 인스턴스가 사용중에 있음을 표시한다.
- 두 번째 상태는 summary phase 로 Heap 에는 왼쪽 영역으로 compaction 된 상태에서 또 다시 Garbase Collection 이 시작된 것이므로, 건드릴 필요가 없는 맨 왼쪽 포인트를 먼저 확인한다. 그리고, 거기서부터 오른쪽으로 조사하면서 살아남은 인스턴스들을 조사한다. 이 상태에서는 Application 실행을 잠시 멈춘 상태에서 하나의 스레드로만 작업을 하는데, 여러 스레드를 사용해서 얻는 이득이 별로 없기 때문이다.
- 세 번째 상태는 compaction phase 로 summary phase 에서 알아낸 정보를 토대로 인스턴스들을 왼쪽으로 최대한 채워서 오른쪽에 최대한 연속된 빈 공간을 만든다. 이 때에도 Application 실행이 잠시 멈춘다.
Concurrent Mark-Sweep Collector (CMS)
- Application 실행속도 보다는 GC 시간을 줄이는 것이 더 좋은 실행환경에 적합하다. 하지만, Heap 크기가 충분히 큰 환경이어야 한다. 명시적으로 지정하려면 -XX:+UseConcMarkSweepGC 옵션을 이용한다. 추가로 incremental mode 를 지정하려면 +XX:+CMSIncrementalMode 옵션을 이용한다.
- Young Generation
- Parallel Collector 와 동일하다.
- Old Generation and Permanent Generation
- 다음과 같은 순서로 작동된다.
- 처음 상태는 initial phase 로 Application 을 실행된 후에 최초로 한 번 실행되며, Application 실행을 잠시 멈추어서 Application 에서 바로 참조가능한 Instance 의 집합을 파악해둔다.
- 다음 상태는 mark phase 로 Application 실행 중 파악된 Set 의 변경사사항을 추적한다.
- 다음 상태는 remark phase 로 Set 에서 추적되지 않은 사항들을 알아내기 위해 Application 실행을 잠시 멈추고, Set 에 포함되지 않은 인스턴스들을 모두 추적한다.
- 다음 상태는 concurrent sweep phase 로 이 때에는 Application 실행이 재개되며, remark phase 에서 파악된 Garbage 들을 청소하는 스레드들도 같이 실행된다.
- CMS 에서는 Compation 을 하지 않기 때문에 다음 그림과 같이 Heap 에 Fragmentation 이 발생한다. 이 빈 공간들은 리스트로 관리되어 운용되는데, 이로 인해 Application 실행속도가 다른 Collector 보다 저하된다. 또한, 메모리 할당을 할 때 충분히 큰 빈 공간이 없으면 Heap 이 계속 커져야 하거나 MemoryOutOfError 가 발생할 수 있으므로, 인접한 빈 공간을 리스트 상에서 합치거나 사용형태에 따라 적절히 빈 공간을 분리해서 낭비를 없애는 작업을 한다.
- 다른 Collector 와는 달리 Old Generation 이 꽉 찼을 때 GC 가 바로 실행되는 것이 아니라 꽉 차기 전부터 지속족으로 GC 가 실행된다. 만약, 꽉 차게 되었을 때에는 Serial Collector 나 Parallel Collector 와 같은 GC 를 실행하게 된다.
Stack 과 Heap 사이즈 지정
Thread Stack Size
- JDK 1.3 까지는 -Xss 와 -Xoss 옵션이 별도로 있어서 각각 native thread stack size 와 java thread stack size 를 지정할 수 있었다.
- 현재는 Java Thread Stack size 와 Native Thread Stack Size 의 구분이 없이 -Xss 옵션만 존재하며, 하나의 Stack 을 이용해서 처리된다. 그래서, 현재는 -Xoss 옵션은 없어졌거나, AIX 같은 경우 하위호환을 위해 남겨두었으나 그 기능은 -Xss 와 동일하다.
Heap
- -Xmx 로 최대치를, -Xms 로 최소치를 지정한다.
Young Generation
- -XX:NewSize 로 최초 실행시의 값을 지정한다.
Young Generation 크기 비율
- -XX:NewRatio 로 지정하며, Old Generation 에 대한 Young Generation 의 상대비율을 지정하는 형식이다. 이 값이 3이면 전체 Heap 영역에서 Young Generation 은 1/4 를 차지하며, Old Generation 은 3/4 를 차지한다.
Survivor 크기 비율
- -XX:SurvivorRatio 로 지정하며, Eden 에 대한 Survivor 의 상대비율을 지정하는 형식이다. 이 값이 7이면 전체 Young Generation 영역에서 Survivor 가 1/9 씩 두 개가 할당되며, Eden 으로 7/9 가 할당된다. (Survivor 는 From 과 To 의 2가지가 있다.)
Permanent Generation 최대 크기
- –XX:MaxPermSize 로 지정하며, 클래스가 로딩되면서 Permanent Generation 이 늘어나는 것의 최대치를 지정한다. Java 5 에서는 기본크기가 64m 이며, 64bit JVM 에서는 30% 더 크다.
JVM 실행중 문제가 발생했을 때의 대처법
JVM 이 실행중 문제가 발생했을 때 다음과 같은 옵션의 사용을 고려해볼 수 있다.
- -XX:+HeapDumpOnOutOfMemoryError
- OutOfMemoryError가 발생했을 때 Java Heap 을 파일에 덤프해준다. 기본으로 꺼져있다.
- -XX:OnOutOfMemoryError="<cmd args>;<cmd args>"
- OutOfMemoryError가 최초 발생했을 때 실행할 스크립트를 복수개 설정할 수 있다.
- -XX:OnError="<cmd args>;<cmd args>"
- JVM 에 fatal error 가 발생했을 때 실행할 스크립트를 복수개 설정할 수 있다.