Historical notes: I added the two-element cache many years ago, assuming that code that repeatedly accessed more than 2 charsets would be rare.
I have been hoping for a high-quality cache implementation to be added to the JDK, perhaps via guava, and to use that in places like Charset. I agree that lookup of non-builtin charsets is heavy-weight. I don't recall anyone trying to optimize the lookup itself. Perhaps you've found an important opportunity to optimize! On Mon, Jan 12, 2015 at 11:09 AM, Bernd Eckenfels <e...@zusammenkunft.net> wrote: > 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 > >