2009년 3월 19일 목요일

JVM Heap Dump를 생성하기 위한 옵션정리

1. Sun JDK

1) HPRof 사용

JDK 버전에 따라 JVM 옵션에 -Xrunhprof:heap=dump,format=b,doe=n (JDK 1.4) 또는 -agentlib:hprof=heap=dump,format=b,doe=n (JDK 1.5)을 명시하고, 실행시에 Control-break 또는 kill -3 명령으로 heap dump를 생성할 수 있다.
Windows 환경이라면 SendSignal.exe를 사용하면 된다.
하지만 오버헤드가 너무 커서 운영환경에서 사용하기에는 무리가 따른다. 이 옵션없이 WAS를 기동하면 30초면 뜨는데, 옵션을 설정하면 무려 3분 30초가 걸렸다.

* 설정
- -Xrunhprof:heap=dump,format=b,doe=n (JDK 1.4)
- -agentlib:hprof=heap=dump,format=b,doe=n (JDK 1.5)
* heap dump 생성
- kill -3
- SendSignal.exe

2) OutOfMemoryError 발생 시 자동으로 heap dump

JVM 옵션에 -XX:+HeapDumpOnOutOfMemoryError를 설정하면 OutOfMemoryError 발생 시에 heap dump를 현재 실행 디렉터리에 생성한다. JBoss의 경우는 $JBOSS_HOME/bin 디렉터리이다. heap dump가 생성되는 경로를 지정하려면 -XX:HeapDumpPath를 설정해준다.
Sun JDK 1.4.2_12, 1.5.0_7, 그리고 HP 1.4.2_11 이후 버전에서 지원된다.

* 설정
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:HeapDumpPath=/path

* heap dump 생성
- OutOfMemoryError 발생시

3) SIGQUIT (kill -3 )

JVM 옵션에 -XX:HeapDumpOnCtrlBreak를 설정하면 SIGQUIT signal로 heap dump를 생성할 수 있다. JDK 1.5.0_14 부터 지원된다. 하지만, Windows와 Linux 버전의 JDK 1.5.0_14는 버그로 인해 "/"가 포함된 파일명으로 heap dump를 생성하려고해 No such file or directory라는 에러를 내며 heap dump가 생성되지 않는다. Solaris 버전은 테스트를 못해봤는데 설마 동작하지 않을까 싶다.

* 설정
- -XX:HeapDumpOnCtrlBreak
* heap dump 생성
- kill -3
- SendSignal.exe

4) jmap 사용

별도로 JVM 옵션에 명시할 필요없이 JDK에 포함되어 있는 jmap을 사용해 heap dump를 생성할 수 있다. Windows 버전은 JDK 1.5 버전에 jmap이 포함되어 있지 않으므로 사용할 수 없다.

* heap dump 생성
- jmap -heap:format=b (JDK 1.5)
- jmap -dump:format=b,file= (JDK 6)

2009년 3월 4일 수요일

IBM-AIX JDK 1.5(SR7), 1.4(SR11) 에서 WebLogic socket leak 해결방법

발생내용
IBM JVM 1.5 SR7, 1.4 SR11에서는 동일 로직임에도 불구하고 hang up 현상이 발생합니다.

원인분석
일반적으로 java에서 close() signal이 발생을 하면, 기존 SR7 이전 버전에서는 native shutdown 루틴은 block되지 않기 때문에 hang up 현상이 발생하지 않았습니다.

하지만 IBM JVM 1.5 SR7, 1.4 SR11에서는 동일 로직임에도 불구하고 hang up 현상이 발생합니다.
타 OS와 비교 분석을 해보면,
일반적으로 다른 OS에서는 java에서 close() 호출 시, native poll에서 “POLLNVAL”이라는 event가 발생한 뒤, socket이 close되는 작업이 수행됩니다.
=========================
POLLNVAL : The specified fd value does not belong to an open file.
This flag is only valid in the revents member; it is not used in the events member.
=========================
하지만 AIX의 경우,
java에서 close를 이벤트로 인식하지 않는 것으로 보여집니다. 때문에 close() 호출 시, native poll에서 특정 이벤트가 발생하지 않고 wait()상태로 전이가 됩니다.

즉, 정리하자면, Java의 close() 후, socket 종료 루틴에 의해 fd를 lock합니다. 하지만 이미 이전에 해당 fd를 관리하는 poll에는 어떠한 이벤트를 발생하지 않기 때문에 hang up현상이 발생하는 것으로 보여집니다.

IBM Java1.5SR7에서 native IO 사용시 hang up이 발생하는 원인은 AIX에서의 java1.5 SR7에서 socket close()시 logic이 변경되어 발생하는 것으로 추정합니다.

UPDATE=======
이슈는 CR370915에서 진행되었던 내용으로,IBM의 AIX JVM 1.5 SR7의 경우 socket close시 hang 현상이 발생하는 문제입니다.
발생하는 경우는,Performance Pack(Native IO)이 on된 상태에서,socket에 대해 polling을 하는 도중에KeepAlive 시간이 경과하여 scheduler가 해당 socket을 close 하려 할 때hang이 되는 현상입니다.

thread dump를 보면 보통 다음과 같은 stack trace를 볼 수 있습니다.
=='[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'' (TID:0x438F2000, sys_thread_t:0x438F9EF8, state:R, native ID:0x0037F035) prio=5
at java/net/PlainSocketImpl.socketClose0(Native Method)at java/net/PlainSocketImpl.socketPreClose(PlainSocketImpl.java:744(Compiled Code))
at java/net/PlainSocketImpl.close(PlainSocketImpl.java:568(Compiled Code))
at java/net/SocksSocketImpl.close(SocksSocketImpl.java:1049(Compiled Code))
at java/net/Socket.close(Socket.java:1341(Compiled Code))
at weblogic/socket/WeblogicSocket.close(WeblogicSocket.java:80(Compiled Code))
at weblogic/socket/SocketMuxer.closeSocket(SocketMuxer.java:449(Compiled Code))
at weblogic/socket/SocketMuxer.cancelIo(SocketMuxer.java:773)
at weblogic/socket/SocketMuxer$TimerListenerImpl.timerExpired(SocketMuxer.java:976(CompiledCode))
at weblogic/timers/internal/TimerImpl.run(TimerImpl.java:273(Compiled Code))
at weblogic/work/SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:464(CompiledCode))
at weblogic/work/ExecuteThread.execute(ExecuteThread.java:197(Compiled Code))
at weblogic/work/ExecuteThread.run(ExecuteThread.java:172(Compiled Code))
'ExecuteThread: '7' for queue: 'weblogic.socket.Muxer'' (TID:0x3511B500, sys_thread_t:0x34FAD6C8, state:R, native ID:0x003E80CB) prio=5
at weblogic/socket/PosixSocketMuxer.poll(Native Method)
at weblogic/socket/PosixSocketMuxer.processSockets(PosixSocketMuxer.java:102)
at weblogic/socket/SocketReaderRequest.run(SocketReaderRequest.java:29)
at weblogic/socket/SocketReaderRequest.execute(SocketReaderRequest.java:42)
at weblogic/kernel/ExecuteThread.execute(ExecuteThread.java:145)
at weblogic/kernel/ExecuteThread.run(ExecuteThread.java:117)
==타이밍 이슈로 IBM AIX 최신 JVM에서만 발생합니다.

WebLogic admin User / Password 재설정 방법

(1). 웹로직 Domain을 Stop시킵니다.
기존의 DefaultAuthenticatorInit.ldift 파일을 backup해둡니다.
파일위치
8.x : {$DOMAIN_HOME}
9.x : {$DOMAIN_HOME}/security/

(2). 도메인 디렉토리 내에 있는 boot.properties 파일을 열고 다음 부분을 수정합니다. (파일이 없을 경우 생성)
[파일위치]
8.x : {$DOMAIN_HOME}
9.x : {$DOMAIN_HOME} <= 없는경우 생성

username=adminuser
password=

(3). 도메인 내의 admin 서버 디렉토리명을 다음과 같이 변경해 줍니다. 다음과 같이 변경하지 않을 경우 서버가 시작되지 않습니다.
8.x : //
=> directory 를 orig 로 이름 변경
9.x : //servers
=> servers directory 를 servers.orig 로 이름 변경

(4). DefaultAuthenticatorInit.ldift 파일의 새로운 패스워드는 암호화가 안되므로 도메인 디렉토리 위치에서 다음의 명령어를 수행하여 패스워드를 보호해줍니다.

java weblogic.security.utils.AdminAccount
(사용예) java weblogic.security.utils.AdminAccount weblogic weblogic .


8.x :
1. {$DOMAIN_HOME}/bin 이동 후 . ./setDomainEnv.sh 실행
2. commnand 상태에서 java weblogic.security.utils.AdminAccount {변경 id} {변경 password} . 실행
3. 현재 디렉토리에 DefaultAuthenticatorInit.ldift 파일생성확인WebLogic admin id/pw change

9.x :
1. {$DOMAIN_HOME}/bin 이동 후 . ./setDomainEnv.sh 실행
2. commnand 상태에서 java weblogic.security.utils.AdminAccount {변경 id} {변경 password} . 실행
3. 현재 디렉토리에 DefaultAuthenticatorInit.ldift 생성확인
4. {$DOMAIN_HOME}/security 디렉토리로 이동 후 생성된 DefaultAuthenticatorInit.ldift 을 복사

(6) Start script 로 기동 후 기동결과 확인완료