Details
-
Bug
-
Resolution: Fixed
-
P3
-
8, 11, 12, 13, 14
-
b21
-
x86_64
-
windows_10
Backports
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8287343 | 11.0.16 | Martin Doerr | P3 | Resolved | Fixed | b05 |
Description
OS: Microsoft Windows 10 pro
Version: 10.0.18362 Number18362
java version "12.0.2" 2019-07-16
Java(TM) SE Runtime Environment (build 12.0.2+10)
Java HotSpot(TM) 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
When a class is dynamically loaded from an external jar, windows locks the jar file. This lock can be removed if the classloader is garbage collected. But if we invoke the method java.beans.Introspector::getBeanInfo on a class coming from the jar file, the classloader can never become garbage collectable.
This problem was first raised in
Indeed, this also happens on Windows and is not just a memory leak, it also prevents the deletion of the jar file.
This is particularly annoying for applications that perform code updates at runtimes or for modular applications that require plugins to be loaded and unloaded.
It should also be noted that file lock does not seem to occur on Linux.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Load a jar file containing a given class. Call java.beans.Introspector.getBeanInfo on this class. The jar file will never be able to be deleted by any technique.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Call java.beans.Introspector.flushCaches methods should clear the cache in "com.sun.beans.introspect.ClassInfo". The jar file can then be deleted.
ACTUAL -
The "com.sun.beans.introspect.ClassInfo" cache is not cleared. The jar file cannot be deleted.
---------- BEGIN SOURCE ----------
SampleObject to be loaded;
package test;
module IntrospectorLeakSampleObject {
exports test;
}
package test;
public class SampleObject {
@Override
public String toString() {
return "SampleObject";
}
}
Loader:
module IntrospectorLeakLoader {
requires java.desktop;
}
package test;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.io.IOException;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.FileSystemException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Set;
public class LeakTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IntrospectionException {
Path testedJar = Paths.get("SampleTest.jar");
Files.copy(Paths.get("Sample.jar"), testedJar, StandardCopyOption.REPLACE_EXISTING);
leakTest(testedJar);
while(true) {
System.gc();
try {
Files.delete(testedJar);
System.out.println("Leak test passed!!!");
break;
}catch(FileSystemException e) {
System.err.println("Leak test failed...");
}
Thread.sleep(1000);
}
}
private static void leakTest(Path testedJar) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IntrospectionException {
ModuleLayer parent = ModuleLayer.boot();
ModuleFinder finder = ModuleFinder.of(testedJar);
ModuleReference a = finder.findAll().iterator().next();
String moduleName = a.descriptor().name();
ModuleLayer moduleLayer = parent.defineModulesWithOneLoader(parent.configuration().resolve(finder, ModuleFinder.of(), Set.of(moduleName)), ClassLoader.getSystemClassLoader());
ClassLoader classLoader = moduleLayer.findLoader(moduleName);
Class<?> c = Class.forName("test.SampleObject", true, classLoader);
System.out.println("Text from loaded object: " + c.getConstructor().newInstance().toString());
Introspector.getBeanInfo(c);
Introspector.flushFromCaches(c);
Introspector.flushCaches();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No obvious workaround. Since the introduction of the modules in java, we can't use reflection on "com.sun.beans.beans.beans.introspect.ClassInfo" without having an IllegalAccessException.
FREQUENCY : always
Attachments
Issue Links
- backported by
-
JDK-8287343 File lock in Windows on a loaded jar due to a leak in Introspector::getBeanInfo
- Resolved
- duplicates
-
JDK-8207331 java.beans.Introspector::getBeanInfo(Class<?>) is causing class to leak
- Closed
- relates to
-
JDK-8207331 java.beans.Introspector::getBeanInfo(Class<?>) is causing class to leak
- Closed
-
JDK-8268554 com.sun.beans.introspect.ClassInfo leaks classes in cache.
- Open
- links to
-
Commit openjdk/jdk11u-dev/22fc6ce7
-
Commit openjdk/jdk/2ee2b4ae
-
Review openjdk/jdk11u-dev/1103
-
Review openjdk/jdk/647