导致崩溃转储的Java错误的解决方法
我开发的一个程序偶尔会因为以下错误而导致JVM崩溃:。不幸的是,甲骨文还没有解决这个错误,错误报告说没有已知的解决办法 我试图通过调用KeyWatcher线程中的.register(sWatchService,eventKinds)来修改bug报告中的示例代码,将所有挂起的注册请求添加到我在KeyWatcher线程中循环的列表中,但它仍然崩溃。我猜这和在sWatchService上同步的效果是一样的(就像提交错误报告的人一样)导致崩溃转储的Java错误的解决方法,java,windows,multithreading,nio,crash-dumps,Java,Windows,Multithreading,Nio,Crash Dumps,我开发的一个程序偶尔会因为以下错误而导致JVM崩溃:。不幸的是,甲骨文还没有解决这个错误,错误报告说没有已知的解决办法 我试图通过调用KeyWatcher线程中的.register(sWatchService,eventKinds)来修改bug报告中的示例代码,将所有挂起的注册请求添加到我在KeyWatcher线程中循环的列表中,但它仍然崩溃。我猜这和在sWatchService上同步的效果是一样的(就像提交错误报告的人一样) 你能想出什么办法来解决这个问题吗?你可能无法解决问题本身,但你可以处
你能想出什么办法来解决这个问题吗?你可能无法解决问题本身,但你可以处理错误并处理它。我不知道您的具体情况,但我可以想象最大的问题是整个JVM的崩溃。将所有内容放在
try
块中不起作用,因为您无法捕获JVM崩溃
由于不了解项目的更多信息,很难提出一个好的/可接受的解决方案,但这可能是一种选择:在单独的JVM进程中完成所有文件监视工作。从主进程启动一个新的JVM(例如使用)。当进程终止(即新启动的JVM崩溃)时,重新启动它。显然,您需要能够恢复,也就是说,您需要跟踪要监视的文件,并且还需要将这些数据保留在主进程中
现在剩下的最大部分是在主进程和文件监视进程之间实现一些通信。这可以使用文件监视过程的标准/或使用/或其他机制来完成。来自评论:
当存在挂起的ReadDirectoryChangesW未完成时,似乎存在I/O取消问题
该语句和示例代码表明,在以下情况下会触发错误:
WatchService.poll()
或WatchService.take()可见,也可能不可见)
WatchKey.cancel()
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您是否考虑过将建议的修复程序发布到邮件列表中?