Charset.lookupViaProviders uses new ServiceLoader instance on each miss.

Bernd Eckenfels ecki at zusammenkunft.net
Mon Jan 12 19:09:48 UTC 2015


Hello,

I see some strange scalability problem in an application which uses a
few exernal Charsets which are provided by ServiceLoader. When I check
the code for Charset.forName()/lookup() I can the 2-entry LRU cache for
charsets, and if those caches do not find the charset, it will check
standard, extended and loaded charsets.

The later function is here:

http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/42770c335bf7/src/java.base/share/classes/java/nio/charset/Charset.java#l341

And it uses ServiceLoader.load() on each lookup.

This is unfortunate as it creates a new ServideLoader instance which in
turn has its own (empty) service provider cache. So every time a
extended charset is loaded (or an unknown charset is requested) it has
to parse all the manifests. But what it is even worse, it also has to
actually instantiate the found provider (again), so in some cases that
provider can also not cache.

Do I read the code correct?

I think a quick fix would be to hold onto the ServiceLoader. Since it
is initialized with the System classloader, there is no need to have a
new one on each load. It migh also be worth considerung another 2-level
LRU cache inside lookupViaProviders. I am not sure if a reload would be
needed for that kind of system serviceloader?

Here is a Java7 stacktrace, I think it has'nt changed much in Java9:


java.lang.Thread.State: RUNNABLE
  at sun.misc.ASCIICaseInsensitiveComparator.isUpper(ASCIICaseInsensitiveComparator.java:89)
  at sun.misc.ASCIICaseInsensitiveComparator.toLower(ASCIICaseInsensitiveComparator.java:93)
  at sun.misc.ASCIICaseInsensitiveComparator.compare(ASCIICaseInsensitiveComparator.java:48)
  at sun.misc.ASCIICaseInsensitiveComparator.compare(ASCIICaseInsensitiveComparator.java:36)
  at java.util.TreeMap.put(TreeMap.java:545)
  at sun.nio.cs.AbstractCharsetProvider.put(AbstractCharsetProvider.java:84)
  at sun.nio.cs.AbstractCharsetProvider.charset(AbstractCharsetProvider.java:98)
  - locked <0x00002b0df808c1e0> (a sun.nio.cs.ext.ExtendedCharsets)
  at sun.nio.cs.ext.ExtendedCharsets.<init>(ExtendedCharsets.java:349)
  at sun.reflect.GeneratedConstructorAccessor398.newInstance(Unknown Source)
  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
  at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
>>at java.lang.Class.newInstance(Class.java:374)
  at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:373)
  at java.util.ServiceLoader$1.next(ServiceLoader.java:445)
  at java.nio.charset.Charset$1.getNext(Charset.java:357)
  at java.nio.charset.Charset$1.hasNext(Charset.java:370)
  at java.nio.charset.Charset$2.run(Charset.java:413)
  at java.nio.charset.Charset$2.run(Charset.java:411)
  at java.security.AccessController.doPrivileged(Native Method)
>>at java.nio.charset.Charset.lookupViaProviders(Charset.java:410)
  at java.nio.charset.Charset.lookup2(Charset.java:487)
  at java.nio.charset.Charset.lookup(Charset.java:475)
  at java.nio.charset.Charset.isSupported(Charset.java:517)
  at sun.nio.cs.StreamDecoder.forInputStreamReader(StreamDecoder.java:68)
  at java.io.InputStreamReader.<init>(InputStreamReader.java:100)

In the specific case it also looks like no thread local decoder was used, but I havent looked into that, yet.

Gruss
Bernd




More information about the core-libs-dev mailing list