JDK-6888768 : DownloadManager causes performance regression in JDK 1.6.0_14
  • Type: Bug
  • Component: performance
  • Sub-Component: libraries
  • Affected Version: 6u14
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_2.5.1
  • CPU: sparc
  • Submitted: 2009-10-06
  • Updated: 2013-11-01
  • Resolved: 2009-12-14
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 6 JDK 7
6u17-rev b09Fixed 7Fixed
Description
Performance regression issue introduced in JDK 1.6.0_10 but found whilst running performance tests on JDK 1.6.0_14.

More info about this problem:

 //sun.misc.Launcher
 protected Class findClass(String name) throws ClassNotFoundException {
 	// Check for download before we look for it. If DownloadManager ends up
 	// downloading it, it will add it to our search path before we proceed
	// to the findClass().
 	DownloadManager.getBootClassPathEntryForClass(name); //<--- Added in JDK 1.6.0_10
 	return super.findClass(name);
 }
 

 //sun.misc.Launcher
 public synchronized Class loadClass(String name, boolean resolve)  throws ClassNotFoundException {
 	DownloadManager.getBootClassPathEntryForClass(name); //<--- Added in JDK 1.6.0_10
 	int i = name.lastIndexOf('.');
 	if (i != -1) {
 		SecurityManager sm = System.getSecurityManager();
 		if (sm != null) {
 			sm.checkPackageAccess(name.substring(0, i));
 		}
 	}
 	return (super.loadClass(name, resolve));
 }
 
 //sun.jkernel.DownloadManager
 public static String getBootClassPathEntryForClass(final String className) {
 	return getBootClassPathEntryForResource(className.replace('.', '/') + ".class"); //<--- this .replace is causing the regression
 }


 //sun.jkernel.DownloadManager
 
 public static String getBootClassPathEntryForResource(final String resourceName) {
 	if (debug)
 		log("Entering getBootClassPathEntryForResource(" + resourceName + ")");
 		if (isJREComplete() || downloading == null || resourceName.startsWith("sun/jkernel")) { //<--- here isJREComplete() is checked which only returns null
 			if (debug)
 				log("Bailing: " + isJREComplete() + ", " + (downloading ==  null));
 			return null;
 		}

...

Introduction of sun.jkernel.DownloadManager.getBootClassPathEntryForClass(name) in both sun/misc/Launcher.findClass and sun/misc/Launcher.loadClass is causing performance regression.

 The above code is what is causing this regression, at least for JRockit which ALWAYS isJREComplete() since -Dkernel.download.enabled=false is always set.
 
 For every class loaded/to be found the className.replace('.', '/') is being
 executed, BEFORE checking the isJREComplete() flag which always is TRUE for
 JRockit. This additional processing causes StringBuilder to be allocated,
 String.replace() to be called as well as StringBuilder.append() just in order
 to return null by checking the isJREComplete() flag.


Thank you
Markus Gronlund
Oracle JRockit

Comments
EVALUATION Adding feedback from Thomas, I will make the suggested changes and test. I think you can simply check isJREComplete() getBootClassPathEntryForClass() to fix this: //sun.jkernel.DownloadManager public static String getBootClassPathEntryForClass(final String className) { if (isJREComplete()) { return null; } return getBootClassPathEntryForResource(className.replace('.', '/') + ".class"); //<--- this .replace is causing the regression }
08-10-2009

WORK AROUND Either improve checking if DownloadManager should be used BEFORE starting to .replace stuff, or remove calls to DownloadManager altogether.
06-10-2009