JDK-8241958 : Slow ClassLoaderReferenceImpl.findType
  • Type: Bug
  • Component: core-svc
  • Sub-Component: debugger
  • Affected Version: 15
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-03-31
  • Updated: 2020-04-15
  • Resolved: 2020-04-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 15
15 b18Fixed
Related Reports
Relates :  
Description
The following was reported Egor Ushakov (JetBrains).

The com.sun.tools.jdi.ClassLoaderReferenceImpl#findType may be slow because ClassLoaderReferenceImpl#visibleClasses does not populate signature and we check it for every class in the loop just after, so requesting all unavailable signatures one by one.

The suggested fix is:
  https://github.com/JetBrains/JetBrainsRuntime/commit/ae823a660ba5ee48ac4d010723b8e33b0db9612b
Comments
URL: https://hg.openjdk.java.net/jdk/jdk/rev/d151c8051bff User: sspitsyn Date: 2020-04-07 07:24:53 +0000
07-04-2020

Yes it is possible, at least one case was discussed within JDK-8181144
01-04-2020

I would even extend the fix to avoid signature-typename conversions: Index: src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java (revision 58628:36500e80f6f177f85582c873f1e9947d47d54dc2) +++ src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java (revision 58628+:36500e80f6f1+) @@ -103,16 +103,22 @@ Type findType(String signature) throws ClassNotLoadedException { List<ReferenceType> types = visibleClasses(); - Iterator<ReferenceType> iter = types.iterator(); - while (iter.hasNext()) { - ReferenceType type = iter.next(); + + // first check already loaded classes and possibly avoid massive signature retrieval later + for (ReferenceType type : vm.classesBySignature(signature)) { + if (types.contains(type)) { + return type; + } + } + + for (ReferenceType type : types) { if (type.signature().equals(signature)) { return type; } } - JNITypeParser parser = new JNITypeParser(signature); - throw new ClassNotLoadedException(parser.typeName(), - "Class " + parser.typeName() + " not loaded"); + + String typeName = new JNITypeParser(signature).typeName(); + throw new ClassNotLoadedException(typeName, "Class " + typeName + " not loaded"); } byte typeValueKey() { Index: src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java (revision 58628:36500e80f6f177f85582c873f1e9947d47d54dc2) +++ src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java (revision 58628+:36500e80f6f1+) @@ -317,12 +317,16 @@ public List<ReferenceType> classesByName(String className) { validateVM(); - String signature = JNITypeParser.typeNameToSignature(className); + return classesBySignature(JNITypeParser.typeNameToSignature(className)); + } + + List<ReferenceType> classesBySignature(String signature) { + validateVM(); List<ReferenceType> list; if (retrievedAllTypes) { - list = findReferenceTypes(signature); + list = findReferenceTypes(signature); } else { - list = retrieveClassesBySignature(signature); + list = retrieveClassesBySignature(signature); } return Collections.unmodifiableList(list); }
01-04-2020

It seems to me that the second loop in the patch is not necessary. Is it possible for a class to not be in vm.classesByName(typeName) but still be in visibleClasses()?
31-03-2020

diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java index 2e21e14f72b..9095393dda1 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java @@ -103,16 +103,21 @@ protected String description() { Type findType(String signature) throws ClassNotLoadedException { List<ReferenceType> types = visibleClasses(); - Iterator<ReferenceType> iter = types.iterator(); - while (iter.hasNext()) { - ReferenceType type = iter.next(); + + // first check already loaded classes and possibly avoid massive signature retrieval later + String typeName = new JNITypeParser(signature).typeName(); + for (ReferenceType type : vm.classesByName(typeName)) { + if (types.contains(type)) { + return type; + } + } + + for (ReferenceType type : types) { if (type.signature().equals(signature)) { return type; } } - JNITypeParser parser = new JNITypeParser(signature); - throw new ClassNotLoadedException(parser.typeName(), - "Class " + parser.typeName() + " not loaded"); + throw new ClassNotLoadedException(typeName, "Class " + typeName + " not loaded"); } byte typeValueKey()
31-03-2020