Created attachment 39554 [details] Speed test A high-volume, latency sensitive application reports that org.apache.jasper.runtime.PageContextImpl.getELContext() uses 0.11% of cpu, of which 0.07% is local to the method. A portion of that comes from iterating across sparse HashSets (packageImports and classImports), the cost of which grows linearly with array size (null buckets are scanned). In the most common case, our JSPs rely on the three auto-generated packages and 1-2 classes. For example, this generated code block from our busiest JSP: static { _jspx_imports_packages = new java.util.HashSet<>(); _jspx_imports_packages.add("javax.servlet"); _jspx_imports_packages.add("javax.servlet.http"); _jspx_imports_packages.add("javax.servlet.jsp"); _jspx_imports_classes = new java.util.HashSet<>(); _jspx_imports_classes.add("com.<proprietary>ViewModel"); _jspx_imports_classes.add("com.<proprietary>Helper"); } Most JVMs initialize HashMap arrays to length 16, so the code above generates one array that is 3/16th full and another that is 2/16th full. Each page request scans the full 16-slot array. A few alternatives exist: 1. Right-size the Set allocation. The entries in the Set are fixed and known at the time of code generation so should be an easy change. 2. Switch to LinkedHashSet<>. Iteration becomes trivial. 3. Combine the two: right-size a LinkedHashSet<>. The attached speed test shows a big improvement with #2 (right-sizing) but a greater improvement from either #1 or #3.
Sorry, error with the numbering in the last sentence: the attached speed test shows a big improvement with #1 (right-sizing) but a greater improvement from either #2 or #3.
Ok, this sounds reasonable looking at the code. https://github.com/apache/tomcat/blob/main/java/org/apache/jasper/compiler/Generator.java#L623
Thanks ! The fix will be in 11.0.0-M17, 10.1.19, 9.0.86 and 8.5.99.
This changed reached prod and had the (small) expected impact. Thanks!