简体   繁体   English

运行新jar文件时openjdk发生致命错误

[英]Fatal errors from openjdk when running fresh jar files

I want to implement an ApplicationChangeMonitor which monitors the filesystem for changes in the currently executed jar file. 我想实现一个ApplicationChangeMonitor ,它监视文件系统中当前执行的jar文件的变化。 When a change is detected the application should restart. 检测到更改时,应用程序应重新启动。 I'm using a WatchService to detect the changes. 我正在使用WatchService来检测更改。

The setup: 设置:

  • Development in (Windows) Eclipse with a workspace on a samba share (Linux system) 在(Windows)Eclipse中开发在samba共享上具有工作空间(Linux系统)
  • The jar file is generated by Eclipse maven (m2e) on that samba share jar文件由Eclipse maven(m2e)在samba共享上生成
  • The jar file is executed from shell on the Linux system (using openjdk) jar文件在Linux系统上从shell执行(使用openjdk)

So everytime a new jar file is created, the running application should be restarted on the Linux system. 因此,每次创建新的jar文件时,都应该在Linux系统上重新启动正在运行的应用程序。 First I tried to make the application restart itself, but most of the times I ran into fatal errors from the JVM. 首先,我尝试使应用程序自行重启,但大多数时候我遇到了来自JVM的致命错误。 Then I chose a simpler approach: I just made the application end itself after a change is detected and implemented the restart mechanism with bash: 然后我选择了一个更简单的方法:我在检测到更改后立即使应用程序结束,并使用bash实现重启机制:

while true ; do java -jar application.jar ; done

The weird thing is, I still get fatal errors once or twice after an application change. 奇怪的是,在应用程序更改后,我仍然会遇到一两次致命错误。 Example: 例:

  • java -jar application.jar <-- initial start, application is running java -jar application.jar < - 初始启动,应用程序正在运行
  • New jar file created 创建了新的jar文件
  • java -jar application.jar <-- fatal error java -jar application.jar < - 致命错误
  • java -jar application.jar <-- fatal error java -jar application.jar < - 致命错误
  • java -jar application.jar <-- application starts java -jar application.jar < - 应用程序启动
  • New jar file created 创建了新的jar文件
  • java -jar application.jar <-- fatal error java -jar application.jar < - 致命错误
  • java -jar application.jar <-- application starts java -jar application.jar < - 应用程序启动

The output: 输出:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGBUS (0x7) at pc=0x00007f46d5e2416d, pid=28351, tid=139942266005248
#
# JRE version: 7.0_25-b30
# Java VM: OpenJDK 64-Bit Server VM (23.7-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libzip.so+0x516d]  Java_java_util_zip_ZipFile_getZipMessage+0x114d
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/workspace/.../target/hs_err_pid28351.log
#
# If you would like to submit a bug report, please include
# instructions on how to reproduce the bug and visit:
#   http://icedtea.classpath.org/bugzilla
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

OpenJDK creates dump files and I guess the relevant part is the stack trace leading to this fatal error: OpenJDK创建转储文件,我猜相关部分是导致此致命错误的堆栈跟踪:

 - Stack: [0x00007fbc9398f000,0x00007fbc93a90000],  sp=0x00007fbc93a8bd90,  free space=1011k
 - Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
 - C  [libzip.so+0x516d]  Java_java_util_zip_ZipFile_getZipMessage+0x114d
 - C  [libzip.so+0x5eb0]  ZIP_GetEntry+0xd0
 - C  [libzip.so+0x3af3]  Java_java_util_zip_ZipFile_getEntry+0xb3
 - j  java.util.zip.ZipFile.getEntry(J[BZ)J+0
 - j  java.util.zip.ZipFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;+38
 - 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
 - j  sun.misc.URLClassPath$JarLoader.getResource(Ljava/lang/String;Z)Lsun/misc/Resource;+48
 - j  sun.misc.URLClassPath.getResource(Ljava/lang/String;Z)Lsun/misc/Resource;+53
 - j  java.net.URLClassLoader$1.run()Ljava/lang/Class;+26
 - j  java.net.URLClassLoader$1.run()Ljava/lang/Object;+1
 - ...

Now, does anyone have any idea why I get these fatal errors? 现在,有没有人知道我为什么会遇到这些致命的错误? I thought maybe it's because the jar file hasn't been written completely (that would explain why the problem comes from Java_java_util_zip_ZipFile_getZipMessage ). 我想也许是因为jar文件还没有写完(这可以解释为什么问题来自Java_java_util_zip_ZipFile_getZipMessage )。 But that's simply not the case because the md5sum of the jar stays the same after executions resulting in fatal errors and working executions. 但事实并非如此,因为jar的md5sum在执行后保持不变,导致致命错误和工作执行。

while true; do md5sum application.jar ; java -jar application.jar ; done

This is because you are getting notified for new file, while that file is being written to disk. 这是因为您正在收到新文件的通知,而该文件正在写入磁盘。 This is bad thing with WatchService, it will notify you as soon as new file gets created but not yet written completely to disk. 这对WatchService来说是件坏事,它会在创建新文件后立即通知您,但尚未完全写入磁盘。

When new jar file is being written to disk, the jar file is locked by process, which is writing that jar file to disk. 当新的jar文件被写入磁盘时,jar文件被进程锁定,进程将该jar文件写入磁盘。 You can't access file till file creator process has not unlocked file. 在文件创建者进程未解锁文件之前,您无法访问文件。

The solution for this: You have to try to open file, if file gets opened then file has been written to disk completely. 解决方案:您必须尝试打开文件,如果文件被打开,则文件已完全写入磁盘。 If you fail to open file, then wait for some time(or dont wait, try next), and try next to open file. 如果您无法打开文件,请等待一段时间(或者不要等待,请尝试下一步),然后尝试打开文件。

To unlock file, implement something like this: 要解锁文件,请执行以下操作:

public void unlockFile(String jarFileName){
    FileInputStream fis = null;
    while(true){
        try{
            // try to open file
            fis = new FileInputStream(jarFileName);
            // you succeed to open file
            // return
            // file will be closed in finally block, as it will always executed
            return;
        }catch(Exception e){
            // file is still locked
            // you may sleep for sometime to let other process finish with file and
            // file gets unlocked

            // if you dont have problem with this process utilizing CPU, dont sleep!
            try{
                Thread.sleep(100);
            }catch(InterruptedException ie){
            }
        }finally{
            if(fis != null){
                try{
                    fis.close();
                }catch(Exception e){
                }
            }
        }
    }

To your problem, 对你的问题,

You told: "I just made the application end itself after a change is detected and implemented the restart mechanism with bash" 你告诉“我刚刚在检测到更改后使应用程序结束,并使用bash实现了重启机制”

So, before you end java process, unlock file as suggested by me in above method. 所以,在你结束java进程之前,按照我在上面的方法中建议的解锁文件。 I am sure errors will go away. 我相信错误会消失。 Just try and let me know results. 试着告诉我结果。

Something like this: 像这样的东西:

void shutDownMethod(){
    // get file name from watcher, below line will depend on your logic and code.
    String jarFileName = watcherThread.getNewNotifiedFile();
    // unlock new jar file.
    unlockFile(jarFileName);
    // shutdown JVM
    System.exit(0);
    // bash will restart JVM
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM