Description
This issue is basically the same as I described in this issue: Related issue
First of all, thank you for making a fix so fast. I have tested the fix and it does not fix the performance issue of the jar class loader on windows. I investigated a bit further. So the fix makes sure the dns lookup is not executed when there is a host. However in my applications all my URL's do not have a host filled in JarFileUrlKey. So the URLS that are saved in the cache all look like this:
- protocol: "nested"
- host: ""
- port: -1
- file: "/C:/work/projects/spring-boot-demo/target/test.jar/!BOOT-INF/lib/spring-boot-3.3.13.jar"
- ref: "null"
I have tested what code in the equals function makes the class loading so slow. It seems to be the synchronized InetAddress getHostAddress()
function in java.net.URL
:
synchronized InetAddress getHostAddress() {
if (hostAddress != null) {
return hostAddress;
}
if (host == null || host.isEmpty()) {
return null;
}
try {
hostAddress = InetAddress.getByName(host);
} catch (UnknownHostException | SecurityException ex) {
return null;
}
return hostAddress;
}
So for the cache the hostAddress
is always null and the host is empty. So it only passes the 2 statements, enters the second one and returns null. The function is synchronized, but it should not have a big impact on performance in this case.
I ran some tests to check performance on the URL class in windows with OpenJDK 17. If I call the hashCode() function on 10,000 URL objects (without host filled) it takes 470ms. When I override the getHostAddress
in the UrlStreamHandler
with the following code:
@Override
protected InetAddress getHostAddress(URL u) {
return getHostAddressSynchronized(u);
}
protected InetAddress getHostAddressSynchronized(URL u) {
synchronized (u) {
if (u.getHost() == null || u.getHost().isEmpty()) {
return null;
}
try {
return InetAddress.getByName(u.getHost());
} catch (UnknownHostException | SecurityException ex) {
return null;
}
}
}
With this override, it only takes 6ms for 10000 hashCode
calls. In a HashMap.putIfAbsent
the difference is even larger (5ms vs 1400ms). I don't understand why this function in URL has such a performance impact (only on windows openjdk). I think it might be a bug in openjdk.
Would it be possible to use an URI or a String as the key type in the cache of JarFileUrlKey
? In my tests that would fix the performance issues with the jar classloader.