Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
导致崩溃转储的Java错误的解决方法_Java_Windows_Multithreading_Nio_Crash Dumps - Fatal编程技术网

导致崩溃转储的Java错误的解决方法

导致崩溃转储的Java错误的解决方法,java,windows,multithreading,nio,crash-dumps,Java,Windows,Multithreading,Nio,Crash Dumps,我开发的一个程序偶尔会因为以下错误而导致JVM崩溃:。不幸的是,甲骨文还没有解决这个错误,错误报告说没有已知的解决办法 我试图通过调用KeyWatcher线程中的.register(sWatchService,eventKinds)来修改bug报告中的示例代码,将所有挂起的注册请求添加到我在KeyWatcher线程中循环的列表中,但它仍然崩溃。我猜这和在sWatchService上同步的效果是一样的(就像提交错误报告的人一样) 你能想出什么办法来解决这个问题吗?你可能无法解决问题本身,但你可以处

我开发的一个程序偶尔会因为以下错误而导致JVM崩溃:。不幸的是,甲骨文还没有解决这个错误,错误报告说没有已知的解决办法

我试图通过调用KeyWatcher线程中的.register(sWatchService,eventKinds)来修改bug报告中的示例代码,将所有挂起的注册请求添加到我在KeyWatcher线程中循环的列表中,但它仍然崩溃。我猜这和在sWatchService上同步的效果是一样的(就像提交错误报告的人一样)


你能想出什么办法来解决这个问题吗?

你可能无法解决问题本身,但你可以处理错误并处理它。我不知道您的具体情况,但我可以想象最大的问题是整个JVM的崩溃。将所有内容放在
try
块中不起作用,因为您无法捕获JVM崩溃

由于不了解项目的更多信息,很难提出一个好的/可接受的解决方案,但这可能是一种选择:在单独的JVM进程中完成所有文件监视工作。从主进程启动一个新的JVM(例如使用)。当进程终止(即新启动的JVM崩溃)时,重新启动它。显然,您需要能够恢复,也就是说,您需要跟踪要监视的文件,并且还需要将这些数据保留在主进程中

现在剩下的最大部分是在主进程和文件监视进程之间实现一些通信。这可以使用文件监视过程的标准/或使用/或其他机制来完成。

来自评论:

当存在挂起的ReadDirectoryChangesW未完成时,似乎存在I/O取消问题

该语句和示例代码表明,在以下情况下会触发错误:

  • 有一个尚未使用的挂起事件(它可能对
    WatchService.poll()
    WatchService.take()可见,也可能不可见)
  • 对键调用
    WatchKey.cancel()
  • 这是一个讨厌的bug,没有通用的解决方法。方法取决于应用程序的具体情况。考虑把手表集中到一个地方,这样你就不需要调用<代码> TabKEY .CopyLe()/<代码>。如果在某一点上池变得太大,请关闭整个
    WatchService
    ,然后重新开始。类似于

    public class FileWatcerService {
        static Kind<?>[] allEvents = new Kind<?>[] {
            StandardWatchEventKinds.ENTRY_CREATE,
            StandardWatchEventKinds.ENTRY_DELETE,
            StandardWatchEventKinds.ENTRY_MODIFY
        };
    
        WatchService ws;
    
        // Keep track of paths and registered listeners
        Map<String, List<FileChangeListener>> listeners = new ConcurrentHashMap<String, List<FileChangeListener>>();
        Map<WatchKey, String> keys = new ConcurrentHashMap<WatchKey, String>();
    
        boolean toStop = false;
    
        public interface FileChangeListener {
            void onChange();
        }
    
        public void addFileChangeListener(String path, FileChangeListener l) {
            if(!listeners.containsKey(path)) {
                listeners.put(path, new ArrayList<FileChangeListener>());
                keys.put(Paths.get(path).register(ws, allEvents), path);
            }
            listeners.get(path).add(l);
        }
    
        public void removeFileChangeListener(String path, FileChangeListener l) {
            if(listeners.containsKey(path))
                listeners.get(path).remove(l);
        }
    
        public void start() {
            ws = FileSystems.getDefault().newWatchService();
            new Thread(new Runnable() {
                public void run() {
                    while(!toStop) {
                        WatchKey key = ws.take();
                        for(FileChangeListener l: listeners.get(keys.get(key)))
                            l.onChange();
                    }
                }
            }).start();
        }
    
        public void stop() {
            toStop = true;
            ws.close();
        }
    }
    
    公共类FileWatcerService{
    静态种类[]allEvents=新种类[]{
    StandardWatchEventTypes.ENTRY\u创建,
    StandardWatchEventTypes.ENTRY\u删除,
    StandardWatchEventTypes.ENTRY\u修改
    };
    WatchService-ws;
    //跟踪路径和注册的侦听器
    Map listeners=新的ConcurrentHashMap();
    映射键=新的ConcurrentHashMap();
    布尔toStop=false;
    公共接口FileChangeListener{
    void onChange();
    }
    public void addFileChangeListener(字符串路径,FileChangeListener l){
    if(!listeners.containsKey(路径)){
    put(path,new ArrayList());
    key.put(path.get(path).register(ws,allEvents),path);
    }
    get(path).add(l);
    }
    public void removeFileChangeListener(字符串路径,FileChangeListener l){
    if(listeners.containsKey(路径))
    get(path).remove(l);
    }
    公开作废开始(){
    ws=FileSystems.getDefault().newWatchService();
    新线程(newrunnable()){
    公开募捐{
    而(!toStop){
    WatchKey=ws.take();
    for(FileChangeListener l:listeners.get(key.get(key)))
    l、 onChange();
    }
    }
    }).start();
    }
    公共停车场(){
    toStop=true;
    ws.close();
    }
    }
    
    我已经设法创建了一个解决方案,尽管它有点难看

    该错误存在于JDK方法
    WindowsWatchKey.invalidate()
    中,该方法释放本机缓冲区,而后续调用仍可能访问它。通过将缓冲区清理延迟到GC来修复此问题

    下面是一个编译到JDK的示例。要应用它,请添加以下Java命令行标志:
    -Xbootclasspath/p:jdk-8029516-patch.jar

    如果修补JDK在您的情况下不是一个选项,那么在应用程序级别仍然有一个解决方法。它依赖于对Windows WatchService内部实现的了解

    public class JDK_8029516 {
        private static final Field bufferField = getField("sun.nio.fs.WindowsWatchService$WindowsWatchKey", "buffer");
        private static final Field cleanerField = getField("sun.nio.fs.NativeBuffer", "cleaner");
        private static final Cleaner dummyCleaner = Cleaner.create(Thread.class, new Thread());
    
        private static Field getField(String className, String fieldName) {
            try {
                Field f = Class.forName(className).getDeclaredField(fieldName);
                f.setAccessible(true);
                return f;
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
        }
    
        public static void patch(WatchKey key) {
            try {
                cleanerField.set(bufferField.get(key), dummyCleaner);
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(e);
            }
        }
    }
    

    注册密钥后立即调用
    JDK_8029516.patch(watchKey)
    ,它将防止
    watchKey.cancel()
    过早释放本机缓冲区。

    Odd。它对我有用。我只是仔细检查了一下。这个链接对我有效,但对我无效。可能是甲骨文的问题。如果看不到代码,很难回答,但要重新安排代码,让一个且只有一个监视线程负责WatchService和WatchKey类。其他线程将通过您的watcher类使用这些类或服务。这是本机内存释放中的一个问题。我怀疑应该归咎于实现malloc/free的Windows库。我会检查您是否拥有最新的DLL,这可能是。@GilbertLeBlanc我尝试在watcher线程中执行所有操作,但有时仍会崩溃。@PeterLawrey是什么让您认为自由是罪魁祸首?这也可能是因为Java试图释放一些它没有malloced的东西。太棒了!它工作得很好。我非常感动和感激!很好@apangin您是否考虑过将建议的修复程序发布到邮件列表中?