jvmcrash의 붕괴 로그 상세 분석 및 주의점
1. error 파일 생성 경로: 매개 변수 설정 - XX:ErrorFile=/path/hs_error%p.log, 기본적으로 Java에서 실행 중인 현재 디렉토리 [default:./hs_err_pid%p.log]
2. 매개 변수-XX:OnError는crash가 종료될 때 명령을 실행할 수 있습니다. 형식은 -XX:OnError="string"입니다.
예:
// -XX:OnError="pmap %p" // show memory map
// -XX:OnError="gcore %p; dbx - %p" // dump core and launch debugger
Linux에서 시스템은 fork에서 셸 명령을 실행하기 위해 하위 프로세스를 내보냅니다. fork로 메모리가 부족할 수 있기 때문에 /proc/sys/vm/overcommit_memory
파라미터를 수정하십시오. 왜 여기에서 vfork를 사용하지 않는지 잘 모르겠습니다.3. -XX:+ShowMessageBoxOnError 매개 변수, jvmcrash 때 linux에서 gdb를 시작하여 분석 및 변조를 합니다. 테스트 환경에서 사용하기에 적합합니다.
오류 파일이 생성되지 않는 경우
linux 커널은 OOM이 발생할 때 프로세스를 강제로 kill합니다./var/logs/messages에서 찾을 수 있습니다.
Error crash 파일의 몇 가지 중요한 부분
a. 오류 정보 개요
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0000000000043566, pid=32046, tid=1121192256
#
# JRE version: 6.0_17-b04
# Java VM: Java HotSpot(TM) 64-Bit Server VM (14.3-b01 mixed mode linux-amd64 )
# Problematic frame:
# C 0x0000000000043566
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
SIGSEGV 잘못된 신호 유형pc는 IP/PC 레지스터 값, 즉 명령을 실행하는 코드 주소입니다.
pid가 프로세스 id입니다.
# Problematic frame:
# V [libjvm.so+0x593045]
문제를 일으키는 동적 링크 라이브러리 함수의 주소입니다.
pc와 +0x593045는 같은 주소를 가리키며, 단지 동적 편이 주소일 뿐이며, 하나는 실행 중인 가상 주소이다
b. 신호 정보
자바에 linux에 등록된 신호 처리 함수, 중간에 2개의 매개 변수 info,ucvoid
static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {
// unmask current signal
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
VMError err(NULL, sig, NULL, info, ucVoid);
err.report_and_die();
}
crash 보고서에서의 신호 오류 알림siginfo:si_signo=SIGSEGV: si_errno=0, si_code=1 (SEGV_MAPERR), si_addr=0x0000000000043566
신호 상세 정보 및si_addr 잘못된 메모리,siginfo_에 저장됨t의 구조체, 즉 신호 등록 함수crash_handler의 매개 변수 info, 내부 핵은 사용자 공간의 신호 구조체에 잘못된 메모리 주소를 저장합니다.siginfo_t, 이렇게 하면 프로세스가 등록된 신호 처리 함수에서 오류를 초래하는 주소를 얻을 수 있습니다.c. 레지스터 정보
Registers:
RAX=0x00002aacb5ae5de2, RBX=0x00002aaaaf46aa48, RCX=0x0000000000000219, RDX=0x00002aaaaf46b920
RSP=0x0000000042d3f968, RBP=0x0000000042d3f9c8, RSI=0x0000000042d3f9e8, RDI=0x0000000045aef9b8
R8 =0x0000000000000f80, R9 =0x00002aaab3d30ce8, R10=0x00002aaaab138ea1, R11=0x00002b017ae65110
R12=0x0000000042d3f6f0, R13=0x00002aaaaf46aa48, R14=0x0000000042d3f9e8, R15=0x0000000045aef800
RIP=0x0000000000043566, EFL=0x0000000000010202, CSGSFS=0x0000000000000033, ERR=0x0000000000000014
TRAPNO=0x000000000000000e
레지스터의 정보는 b부분의 신호 처리 함수 인자(ucontext_t*) usVoid에 저장됩니다.X86 아키텍처:
void os::print_context(outputStream *st, void *context) {
if (context == NULL) return;
ucontext_t *uc = (ucontext_t*)context;
st->print_cr("Registers:");
#ifdef AMD64
st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]);
st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]);
st->cr();
st->print( "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]);
st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]);
st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
st->cr();
st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
st->cr();
st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]);
st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]);
st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]);
st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);
st->cr();
st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]);
st->print(", EFL=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]);
st->print(", CSGSFS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_CSGSFS]);
st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]);
st->cr();
st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]);
#else
st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]);
st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]);
st->print(", ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ECX]);
st->print(", EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDX]);
st->cr();
st->print( "ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_UESP]);
st->print(", EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBP]);
st->print(", ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESI]);
st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]);
st->cr();
st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]);
st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2);
st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]);
#endif // AMD64
st->cr();
st->cr();
intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp);
print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t));
st->cr();
// Note: it may be unsafe to inspect memory near pc. For example, pc may
// point to garbage if entry point in an nmethod is corrupted. Leave
// this at the end, and hope for the best.
address pc = os::Linux::ucontext_get_pc(uc);
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
print_hex_dump(st, pc - 16, pc + 16, sizeof(char));
}
레지스터의 정보는 오류를 분석할 때 매우 중요하다실행 부근의 일부 기계 코드를 출력하다
Instructions: (pc=0x00007f48f14ef51a)
0x00007f48f14ef4fa: 90 90 55 48 89 e5 48 81 ec 98 9f 00 00 48 89 bd
0x00007f48f14ef50a: f8 5f ff ff 48 89 b5 f0 5f ff ff b8 00 00 00 00
0x00007f48f14ef51a: c7 00 01 00 00 00 c6 85 00 60 ff ff ff c9 c3 90
0x00007f48f14ef52a: 90 90 90 90 90 90 55 48 89 e5 53 48 8d 1d 94 00
instruction 부분에서 기계 코드가 출력됩니다.형식
:
첫 번째는udis 라이브러리에 있는udcli 도구를 사용하여 어셈블리명령:
echo '90 90 55 48 89 e5 48 81 ec 98 9f 00 00 48 89 bd' | udcli -intel -x -64 -o 0x00007f48f14ef4fa
해당하는 어셈블리 표시두 번째는 쓸 수 있어요.
objectdump -d -C libjvm.so >> jvmsodisass.dump
오프셋 주소 0x593045를 찾습니다. 바로 당시 실행된 어셈블리입니다. 그리고 상하문과 결합하여 원본 코드로 문제의 문장을 추측합니다.d. 레지스터에 대응하는 메모리의 값
RAX=0x0000000000000000 is an unknown value
RBX=0x000000041a07d1e8 is an oop
{method}
- klass: {other class}
RCX=0x0000000000000000 is an unknown value
RDX=0x0000000040111800 is a thread
RSP=0x0000000041261b88 is pointing into the stack for thread: 0x0000000040111800
RBP=0x000000004126bb20 is pointing into the stack for thread: 0x0000000040111800
RSI=0x000000004126bb80 is pointing into the stack for thread: 0x0000000040111800
RDI=0x00000000401119d0 is an unknown value
R8 =0x0000000040111c40 is an unknown value
R9 =0x00007f48fcc8b550: <offset 0xa85550> in /usr/java/jdk1.6.0_30/jre/lib/amd64/server/libjvm.so at 0x00007f48fc206000
R10=0x00007f48f8ca7d41 is an Interpreter codelet
method entry point (kind = native) [0x00007f48f8ca7ae0, 0x00007f48f8ca8320] 2112 bytes
R11=0x00007f48fc98f270: <offset 0x789270> in /usr/java/jdk1.6.0_30/jre/lib/amd64/server/libjvm.so at 0x00007f48fc206000
R12=0x0000000000000000 is an unknown value
R13=0x000000041a07d1e8 is an oop
{method}
- klass: {other class}
R14=0x000000004126bb88 is pointing into the stack for thread: 0x0000000040111800
R15=0x0000000040111800 is a thread
jvm는 레지스터의 값을 통해 대응하는 대상을 찾는 데 좋은 참고가 될 수 있습니다e. 기타 정보
error 안에 일부 라인 정보, 그리고 당시 메모리 이미지 정보도 있는데 이것들은 모두 분석의 일부분으로 참고할 수 있다
crash 보고서는 당시의 상황을 대략적으로 반영할 수 있다. 특히 코어덤프가 없을 때 분석에 도움이 되지만 코어덤프가 있다면 최종적으로 코어덤프는 문제의 원인을 신속하고 정확하게 발견할 수 있다.
이상은 본문의 전체 내용입니다. 본고의 내용이 여러분의 학습이나 업무에 일정한 도움을 줄 수 있는 동시에 저희를 많이 지지해 주시기 바랍니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
자바 문자열 풀우리는 Java에서 문자열이 힙 메모리 영역에 저장된다는 것을 알고 있습니다. 이 힙 메모리 내부에는 String Pool이라는 특정 메모리 영역이 있습니다. 문자열 프리미티브를 생성하면 자바 문자열의 불변성 덕분에...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.