수정된 JAR파일로 인한 JVM 충돌문제
hs_err_pid 파일을 열어보면
# A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0xff380700, pid=583, tid=3156104 # # JRE version: 6.0_16-b01 # Java VM: Java HotSpot(TM) Server VM (14.2-b01 mixed mode solaris-sparc ) # Problematic frame: # C [libc_psr.so.1+0x700] memcpy+0x2f8 ... --------------- T H R E A D --------------- Current thread (0x00746400): JavaThread "p: default-threadpool; w: Idle" daemon [_thread_in_native, id=3156104, stack(0xb0c00000,0xb0c80000)] siginfo:si_signo=SIGSEGV: si_errno=0, si_code=1 (SEGV_MAPERR), si_addr=0xfe0cc000 Registers: O0=0xfe0cbfc0 O1=0x00000000 O2=0xc3230063 O3=0x6f727465 O4=0x6d612f67 O5=0x70726f63 O6=0xb0c7c890 O7=0xfe202378 G1=0x00054000 G2=0x00c4f5d0 G3=0x00000000 G4=0xff140000 G5=0x03785238 G6=0x00000000 G7=0xb7314200 Y=0x00000000 PC=0xff380700 nPC=0xff380704 Top of Stack: (sp=0xb0c7c890) 0xb0c7c890: fe0c77d2 00000008 00000065 00007200 0xb0c7c8a0: 00000072 96898d9b ffffffff 00000000 0xb0c7c8b0: 03789a00 fe0cbfc0 0000002c 00001d80 0xb0c7c8c0: ff3303a8 00000000 b0c7c8f0 fe20d194 0xb0c7c8d0: 00c4f5e4 00000000 00000001 00000000 0xb0c7c8e0: 00000000 00000000 00000001 00c4f608 0xb0c7c8f0: fe0c77d2 00000076 00000065 00007200 0xb0c7c900: 00000072 96898d9b ffffffff 00000000 Instructions: (pc=0xff380700) 0xff3806f0: d8 5e 60 30 da 5e 60 38 d6 f6 20 20 d8 f6 20 28 0xff380700: d4 5e 60 40 d6 5e 60 48 da f6 20 30 d4 f6 20 38 Stack: [0xb0c00000,0xb0c80000], sp=0xb0c7c890, free space=498k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [libc_psr.so.1+0x700] memcpy+0x2f8 C [libzip.so+0xd19c] C [libzip.so+0x2380] ZIP_GetEntry+0xe4 C [libzip.so+0x2800] Java_java_util_zip_ZipFile_getEntry+0xc4 j java.util.zip.ZipFile.getEntry(JLjava/lang/String;Z)J+0 j java.util.zip.ZipFile.getEntry(JLjava/lang/String;Z)J+0 j java.util.zip.ZipFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;+31 j java.util.jar.JarFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;+2 j java.util.jar.JarFile.getJarEntry(Ljava/lang/String;)Ljava/util/jar/JarEntry;+2 ... 위와 비슷한 내용이 보인다면
원인
JVM 충돌
해결하기
가장 흔한 이유는 아래 2가지가 있습니다.
1. 기기의 SWAP 공간이 부족
2. JVM에서 해당 JAR 파일이 사용중일때 JAR 파일이 수정되거나 덮어쓰여졌을 경우, JAR 파일이 손상됐다고 판단.
1번의 이슈같은 경우는 논외로 하겠습니다.
2번의 이슈가 거의 대부분인데 이유는 아래와 같습니다.
JVM은 성능향상을 목적으로 JAR 파일의 central directory structure(mmap를 사용하여)를 캐싱합니다.
central directory는 JAR파일의 내용(엔트리 주소, 사이즈같은)을 담고있는데 그것을 캐싱한다는 것은 매번 JAR파일의 엔트리를 사용할때마다 디스크 에서 읽는것을 없애줍니다.
그런데 만일 JAR파일이 수정되었다면 JAM의 central directory는 더이상 정확한 정보를 가지지 못하게되고 결과적으로 수정된 JAR파일에서 엔트리를 로딩하려 할때 SIGBUS나 SIGSEGV를 발행하게됩니다.
참고 : 1.6.0_23 부터 ZIP/JAR 파일에 대하여 메모리 매핑을 사용하지않는 명령행 옵션이 추가되었습니다.
-Dsun.zip.disableMemoryMapping=true
상기 옵션을 사용하게 되면 성능에 영향을 끼치게되는데 이유는 VM이 매번 JAR의 엔트리를 사용할때마다 추가적인 디스크 IO가 발생되기때문입니다(central directory structrure 를 알아내기 위하여).
가급적 새롭게 JAR파일을 배포하게되면 해당 JAR파일을 사용하여 실행되고 있는 프로세스를 재시작하는것을 추천합니다.
참고