Udało mi się utworzyć obejście, chociaż jest ono nieco brzydkie.
Błąd jest w metodzie JDK WindowsWatchKey.invalidate()
, która zwalnia macierzysty bufor, podczas gdy kolejne wywołania mogą nadal uzyskiwać do niego dostęp. This one-liner rozwiązuje problem, opóźniając czyszczenie bufora aż do GC.
Tutaj jest skompilowany patch do JDK.W celu zastosowania go dodać następujące Java wiersza polecenia flag
-Xbootclasspath/p:jdk-8029516-patch.jar
Jeśli łatanie JDK nie jest rozwiązaniem w przypadku, nadal istnieje obejście na poziomie aplikacji. Opiera się na wiedzy na temat wewnętrznej implementacji 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);
}
}
}
połączeń JDK_8029516.patch(watchKey)
zaraz po klucz jest zarejestrowany i będzie zapobiegać watchKey.cancel()
od zwolnieniu natywną bufor przedwcześnie.
Nieparzysty. Mi to pasuje. Właśnie sprawdziłem dwa razy. – Yrlec
Link zadziałał i nie zadziałał u mnie. Prawdopodobnie problem z Oracle. Nie widząc kodu, trudno jest odpowiedzieć, ale zmienić swój kod tak, aby miał ** jeden i tylko jeden wątek ** odpowiedzialny za klasy WatchService i WatchKey. Inne wątki będą używać tych klas lub usług za pośrednictwem klasy obserwatora. –
Jest to problem z pamięcią zwalniającą pamięć rodzimą. Podejrzewam, że jest to biblioteka Windows, która implementuje malloc/free, która jest winna. Sprawdziłbym, czy masz najnowszą bibliotekę DLL. –