Tagged: 자바

[발 번역] 자바 가비지 컬렉션

이글은 Garbage Collectors Available In JDK 1.7.0_04 를 발 번역한 것입니다.

Jack Shirazi 씨는 가비지 컬랙터가 무엇이고 오파클 자바 7 업데이트 4 JVM 에서 활용할 수 있는 가비지 컬렉터 조합에 대해서 말해줄 것입니다.

Published June 2012, Author Jack Shirazi

마침내 G1 을 공식적으로 – i.e. 더 이상 실험적 가비지 컬렉터가 아니다 – 1.7.0_04 (Java 7 update 4) 릴리즈에서 지원되며 이것은 이제 Sun JVM 의 가비지 컬렉터 측면에서 활용가능한 가치있는 주식(?)을 가지는 중임을 말한다. 아래에 기술할 자세한 사항은 다른 많은 Sun JVM 버전에 적용가능성이 높지만 특별히 Sun 1.7.0_04 JVM 과 연관된다.

현재 7개의 주요한 가비지 컬렉션 알고리즘이 있고 그중에 하나는(PS Scavenge), 우리가 두가지 다른 알고리즘으로 부르는(adaptive GC 를 가진것과 가지지 않은것), 확실히 다른 두가지 모드(Mode)를 가지고 있고 아주 많은 옵션들을 가지는 다른것들은(concurrent collector) 실질적으로 나머지 절반의 알고리즘을 구성한다. 이것은 우리가 여기서 해야할 가비지 컬렉터 리스트를 위해 유용하다.

첫째로, 나는 실질적으로 다른 주요한 가비지 컬렉터들을 특징지을 것이다. 그것은 7가지다.(나는 G1 컬렉터까지 포함했다.)

Garbage CollectorGeneration
CopyYoung generation
PS ScavengeYoung generation
ParNewYoung generation
G1 Young GenerationYoung generation
PS MarkSweepOld generation
ConcurrentMarkSweepOld generation
G1 Mixed GenerationOld generation

Young generation collectors

Copy (enabled with -XX:+UseSerialGC)

the serial copy collector는 에덴(Eden) 영역에서 살아남은 객체들을 Survivor space로 복사하기 위해서 그리고 Survivor space 사이에서 객체들을 old generation 으로 복사할 시점에서 충분히 오랫동안 객체가 존재하는지 결정될때까지 하나의 쓰레드(thread)를 사용합니다.

PS Scavenge (enabled with -XX:+UseParallelGC)

the parallel scavenge collector 는 복사 컬렉터(the serial Collector)와 유사하지만 병렬로 여러개의 쓰레드를 사용하고 old generation 을 수집하는 방법에 대한 몇가지 지식을 가지고 있다. (기본적으로 serial 과 PS old gen 컬렉터를 함께 동작하도록 작성하라)

ParNew (enabled with -XX:+UseParNewGC)

the parallel copy collector 는 복사 컬렉터(the serial Collector)와 유사하지만 병렬로 여러개의 쓰레드를 사용하고 old generation collector 가 수집하는 객체에서 작동하도록 허용한 내부 콜백(callback)을 허용한다. (실제로 concurrent collector와함께 동작하도록 작성하라)

G1 Young Generation (enabled with -XX:+UseG1GC)

the garbage first collector 는 힙영역을 수 많은 작은 공간으로 나누는 ‘Garbage First’ 알고리즘을 사용하지만 이것은 여전히 G1 을 위해서 young genration 을 Eden 영역과 Survivor space로 나눈다.

Old generation collectors

MarkSweepCompact (enabled with -XX:+UseSerialGC)

the serial mark-sweep collector는, 모든 컬렉터의 아버지, 옵션으로 압축(compaction) 기능을 가지는 시리얼(하나의 쓰레드) 풀 mark-sweep 가비지 컬렉션 알고리즘을 사용한다.

PS MarkSweep (enabled with -XX:+UseParallelOldGC)

the parallel scavenge mark-sweep collector, MarkSweepCompact 의 패러럴 버전이다.

ConcurrentMarkSweep (enabled with -XX:+UseConcMarkSweepGC)

the concurrent collector, 컬렉션이 동작하는 동안 애플리케이션 쓰레드들이 정지 없이 백그라운드로 대부분의 가비지 컬렉션 작업을 하도록 시도하는 가비지 컬렉션 알고리즘이다. (여전히 애플리케이션 쓰레드가 정지되는 단계가 있지만 이러한 단계는 최소로 유지되도록 시도된다.) 주의할 것은 concurrent collector 가 가비지를 수집에 실패한다면, 다음번 GC를 위한 the serial MarkSweepCompact collector 도 실패한다.

G1 Mixed Generation (enabled with -XX:+UseG1GC)

the garbage first collector는 힙(heap)을 아주 많은 작은 공간들로 나누는 ‘Garbage First’ 알고리즘을 사용한다.

ConcurrentMarkSweep 제외한 모든 가비지 컬렉션 알고리즘은 stop-the-world 고, i.e 그들이 동작하는 동안에 모든 애플리케이션 쓰레드들을 정지시킨다 – 정지(the stop)은 ‘멈춤시간(pause time)’ 으로 알려져 있다. ConcurrentMarkSweep 는 모든 작업을 백그라운드로 동작하고 멈춤시간을 최소화하도록 노력하지만 이 컬렉션도 stop-to-world 단계를 가지며 완전한 stop-the-world 를가지는 MarkSweepCompact 가 실패할수 있다.

Combinations of Garbage Collectors

그것은 활용할 수 있는 가비지 컬렉션의 집합이지만, 그들은 두개의 서로다른 힙(heap) 공간에서 운영되고 이것은 우리가 실제로 특정한 JVM 세팅을 가지는 조합이며, 그래서 나는 가능한 조합들을 보여줄 것이다. 이것은 이러한 모든 컬렉션들은 서로함께 동작하기 때문에 여러 묶음 조합이 나올수 없다. G1 다른것들과 동작하지 않는 반사회적(antisocial) 컬렉터이고 the serial collector 는 최후의 보루 컬렉터, ‘PS’ 컬렉터는 다른 것들과 함께 동작하는게 좋고 ParNew 와 Concurrent는 서로함께 동작하는게 좋다. 물론 이렇게 아주 단순화 할수는 없지만, 그래서 여기에 내가 생각하는 가비지 컬렉션 알고리즘 옵션들내에 메인 옵션 리스트들이다. 퀴즈의 비트를 좋아하는 부류의 사람들에게서는, 다양한 JVMS 들에서 -Xincgc 와 -XX:+UseTrainGC 사용해 활용할 수 있는(이러한 플래그는 더 이상 유용하지 않으며 정식 플래그에서는 ParNew 와 Concurrent 를 사용하는것으로 변경되었으며 -XX:+UseTrainGC 플래그는 이 JVM에서 시작시 에러를 발생시킨다) “train” 가비지 컬렉터를 우리는 시간이 지남에따라 잃어버렸다.

GC 알고리즘을 조합해 동작할 수있는 Full list:

Command Options (1)Resulting Collecto Combination
-XX:+UseSerialGCyoung Copy and old MarkSweepCompact
-XX:+UseG1GCyoung G1 Young and old G1 Mixed
-XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicyyoung PS Scavenge old PS MarkSweep with adaptive sizing
-XX:+UseParallelGC -XX:+UseParallelOldGC -XX:-UseAdaptiveSizePolicyyoung PS Scavenge old PS MarkSweep, no adaptive sizing
-XX:+UseParNewGCyoung ParNew old MarkSweepCompact
-XX:+UseParNewGC -XX:+UseConcMarkSweepGCyoung ParNew old ConcurrentMarkSweep (2)
-XX:-UseParNewGC -XX:+UseConcMarkSweepGCyoung Copy old ConcurrentMarkSweep (2)
(1) 이 리스트들의 모든 조합은 오직 -XX:+UseConcMarkSweepGC 와 조합할 수 있는 -XX:+UseParNewGC를 제외하고 이 리스트에 없는 다른 GC 알고리즘을 추가하하고 JVM을 시작시키면 실패할 것이다.
(2) 알고리즘을 바꾸는 -XX:+UseConcMarkSweepGC 와 함께 사용할 경우 아주 아주 많은 옵션들이 있다. 예를들어
* -XX:+/-CMSIncrementalMode - an incremental concurrent GC algorithm 를 사용 혹은 비활성.
* -XX:+/-CMSConcurrentMTEnabled - parallel (multiple threads) concurrent GC algorithm 을 사용 혹은 비활성.
* -XX:+/-UseCMSCompactAtFullCollection - Full GC가 발생할때 압축(compaction)을 사용 혹은 비활성

위와 똑같은 다른 옵션들

Command Options Used On Their OwnEquivalent To Entry In Table Above
-XX:+UseParallelGC-XX:+UseParallelGC -XX:+UseParallelOldGC
-XX:+UseParallelOldGC-XX:+UseParallelGC -XX:+UseParallelOldGC
-Xincgc-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
no option on most Windows-XX:+UseSerialGC (see also this page)
no option on most Unix-XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy (see also this page) - 역주) 이것은 잘못된 내용이다. Java 버전에 따라 Default 옵션이 다르다.
-XX:+AggressiveHeapOS와 어떻게 서로 상호작용하고 메모리와 쓰레드의 크기와 연관된 옵션들의 묶음인 -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy

JAVA에서 스크린 Refresh 하기

리눅스 터미널에서 실행되는 각종 모니터링 프로그램들을 보면 화면이 그대로 인채 수치만 바뀌는 형식을 취하는 프로그램들이 많다. 사실 터미널 스크린을 빠르게 Refresh 하는것인데, 자바에서는 다음과 같이 프로그래밍을 하면 된다.

Console 객체를 이용해 구현한다.

Jmxterm – 커맨드 라인 JMX

JAVA 에는 JMX(Java Management Extension) 이라고해서 JAVA 애플리케이션을 관리하기 위한 확장을 제공합니다. JAVA 애플리케이션을 시작할때에 다음과 같이 JVM 옵션을 주게되면 사용할 수 있습니다.

  • -Dcom.sun.management.jmxremote
  • -Dcom.sun.management.jmxremote.port
  • -Dcom.sun.management.jmxremote.authenticate
  • -Djava.rmi.server.hostname
  • -Dcom.sun.management.jmxremote.ssl

hostname, port 그리고 authenticate 을 설정하면 특정 호스트에서 특정포트를 통해서 인증을 통해서 JMX 클라이언트를 통해서 접속할 수 있는데, JMX 클라이언트로 가장 유명한 것이 JConsole 입니다.

jconsole

그런데, 보안상의 이유로 JMX 는 활성화하되 접속은 로컬호스트에서만 되도록 설정을 해놓는 경우가 많습니다. 다음과 같이 말입니다.

대부분의 로컬호스트가 리눅스일 경우에는 JConsole 을 이용하기 위해서는 터미널의 터널링을 해주는 방법등을 동원하는데 JConsole 이 아닌 jmxterm 프로그램을 이용하면 리눅스 터미널에서 jmx 를 활용할 수 있습니다.

jmxterm

jmxterm 은 JMX Terminal 로 자바로 작성된 커맨드 라인 JMX 클라이언트 입니다. 다른 추가적인 라이브러리가 필요없이 jdk 만 있으면 동작하고 사용자와 상호작용을 할수 있도록 Interactive 하게 동작합니다.

또, JMX 서버 설정대로 인증을 할 수 있고 로컬호스트라면 JAVA 애플리케이션의 PID 를가지고 접속을 할수 있습니다.

Interactive 작업시 탭키(Tab key) 를 이용한 자동완성기능(Auto completion)을 제공합니다. 따라서 MBean domain 이나 Beans 들을 전부 외울 필요가 없습니다.

다운로드 

다운로드는 다음의 주소에서 다운받을 수 있습니다.

사용방법.

이제부터 간단한 예제를 통해서 어떻게 사용하는지 알아보겠습니다.  먼저 Tomcat 을 실행하는데, JMX 를 로컬호스트를 통해서만 접속할 수 있도록 옵션을 주고 실행했습니다. 다음과 같이 말이지요.

JMX 포트는 8090 이고 인증은 없으며 로컬호스트에서만 접속되도록 했습니다.

이제 jmxterm 을 실행합니다.

위와같이 $> 프롬프트가 나옵니다. 여기서 이제 JMX로 접속을 해야 합니다. 프롬프트에서 다음과 같이 입력을 합니다.

접속방법은 위와같이 “open 로컬아이피:포트” 형식입니다. 만일 Tomcat 의 PID 를 알고 있다면 “open PID” 형식으로도 접속을 할 수 있습니다.

이제부터는 JMX 의 MBeans Domain, Beans 를 이용해서 JMX 의 속성들을 찾을 수 있습니다. 먼저 Domain 목록은 다음과 같이 조회를 합니다.

domain 리스트를 확인했으니 domain 을 지정할려면 “domain 도메인명” 을 입력해주면 됩니다.

domain을 지정했으니 이제는 bean 들을 볼 수 있습니다. 다음과 같이 합니다.

그럼 Bean 을 지정할려면 어떻게 해야할까요? 짐작대로 “bean 빈명” 해주면 됩니다.

bean 은 각종 속성과 액션들을 가지고 있는 셋트입니다. 이들을 보기 위해서는 info 명령어를 사용합니다.

위와같이 bean 에 속하는 속성들을 볼 수 있고 액션도 볼수 있습니다.(위 예제에서는 액션은 안나왔네요.)

속성이 가지고 있는 값을 보기 위해서는 “get 속성” 을 해주시면 됩니다.

각 속성들은 리턴타입에 맞게 화면에 표시됩니다.

이렇게 리눅스 터미널에서도 얼마든지 JMX 를 이용할 수 있습니다.

Java 디폴트 옵션 알아내기.

Java 로 프로그램을 실행할때에는 많은 옵션들을 줄 수가 있다. 대표적으로 최소, 최대 힙(Heap) 크기와 가비지 컬렉터(Garbage Collector)를 무엇으로 할 것인지 하는 것이다.

그런데, 이러한 옵션들이 없다면 Java 는 기본적으로 어떤 값으로 동작을 하게될까? 이 물음에 대한 답은 다음의 명령어로 알아 볼 수 있다.

위와 같이 실행을 하면 기본적인 값들을 보여준다. 다음은 Linux X86_64 에서 Java 버전별로 가지는 기본값들 이다.

jdk1.6.0_45

jdk1.7.0_75

jdk1.8.0_40

 

JMX 로 Tomcat 모니터링 하기.

tomcat

톰캣(Tomcat)은 JEE의 Web Container 의 구현에 입니다. 흔히 WAS 서버라고 하죠. 많은 기능이 있지만 이번에는 JMX를 설정하고 이를 이용해서 Tomcat 을 모니터링 해보겠습니다.

JMX는 Java Management eXtension 으로 자바 서비스들을 관리하고 모니터링하기위한 API를 제공하는 기능을 포함하는 기술입니다. Tomcat 오 자바 서비스의 일종임으로 JMX를 이용할 수 있습니다.

톰캣(Tomcat)의 경우에 아쉽게도 기본 배포본에 이를 위한 라이브러리가 포함되어 있지않아 이 기능을 이용하기 위해서는 톰캣용 JMX 라이브러리를 다운받고 톰캣을 재시작 해줘야 합니다.

이 파일을 톰캣(Tomcat) 라이브러리 디렉토리인 lib 에 넣어줍니다.

그리고 톰캣(Tomcat)시작 스크립트에 다음과 같이 JMX 파라메터를 넣어줍니다.

여기서 주의해야할 것은 ‘192.168.96.6’ IP주소는 실제 톰캣(Tomcat)서버가 동작하는 서버의 IP주소로 바꿔야 한다는 것입니다.

그리고 다음과 같이 server.xml 파일에서 Server 섹션에 JMX 설정을 해줍니다.

이렇게 한다음에 톰캣(Tomcat)을 재시작해주면 됩니다.

JMX 는 위 server.xml 설정에서 정의한 두가지 포트를 사용합니다. 여기서는 9180, 9181이 그렇습니다. 리눅스, 윈도우즈 서버라면 반드시 방화벽에서 위 포트를 허용하는 것을 잊지 말아야 합니다.

이제 자바가 설치된 컴퓨터에서 jconsole 을 실행해서 ‘JMX서버아이피주소:9180’ 으로 접속을 시도합니다.(설정에서 인증을 빼버렸기 때문에 아이디/패스워드를 입력할 필요가 없습니다.)

jconsole접속을 완료하면 다음과 같이 192.168.96.6 에서 동작하는 톰캣(Tomcat)서버를 모니터링하고 관리할 수 있게 됩니다.

JMX

jstack 과 thread Id, CPU, Mem 사용량 체크.

jstack 은 자바 애플리케이션의 쓰레드(Thread) 덤프를 뜰 수 있도록 도와주는 도구 입니다. 자바 애플리케이션의 쓰레드의 상태를 상세히 알 수 있어서 자바 애플리케이션의 프로파일링을 할 수 있고 이를 통해서 성능을 개선할 수 있습니다.

예를들면 다음과 같습니다.

문제는 이렇게 jstack 의 결과을 보면 당시 쓰레드에 OS 의 자원사용량을 알 방법이 없습니다. OS의 자원이라고 하면 CPU, MEM 등과 같은 것입니다.

jstack  의 결과에는 tid 라고 해서 Thread ID 가 헥사(16 진수)로 표시됩니다. 이는 OS상에서 자바 애플리케이션의 쓰레드의 PID 를 가리킵니다.

그래서 jstack 을 이용할때에 top 명령어를 이용해서 로그를 나기고 이둘을 스크립트를 이용해서 조합해서 가지고 올 수 있도록 누군가 만들었더군요.

stack overflow: Inspecting Java threads in Linux using top

답변을 다신분의 스크립트는 다음과 같습니다.

결과는 다음과 같이 나옵니다.