Bug 63661

Summary: StandardRoot.java#getResource Method, loading of jar is slow and recursive from lib folder of application
Product: Tomcat 9 Reporter: Dupinder Singh <dupinderdhiman5>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED INVALID    
Severity: critical    
Priority: P2    
Version: 9.0.22   
Target Milestone: -----   
Hardware: PC   
OS: All   
Attachments: screenShot visualVM

Description Dupinder Singh 2019-08-13 12:06:22 UTC
Created attachment 36716 [details]
screenShot visualVM

My Application:
my application is Java WebApplication, Using Tomcat9 and OpenJDK11 with Velocity Template Engine and core java for DB interactions, Jquery for front-end.
I deploy my application as a docBase application, not like a war file

----------------------------------------------------------------------------------

Problem: My application has performance issues. Http requests from the browser are slow, basically, backend(Java) taking time to create a response for HTTP request.

So I drilled down and use VisualVM to look into the main problem area.

I found that my application code is not taking time, its something else, so the issue is because of  StandardRoot.java#getResource Method loads the jars for every HTTP Request. to resolve this problem I read some of the articles and Stackoveflow Answers, that helped but partially, issue fixed but not really.

--------------------------------------------------------------------------------
So let's talk about the solution: Solution is to increase the CacheTTL (Cache time to live).
Basically, the problem is CacheTTL is 5 seconds by default, Tomcat load class from the jar only for 5 seconds if the application needs a class again, Tomcat will again load a class from the jar. which is a recursive process, so I tried to increase the CacheTTL to 30 days. and it worked well. Now Tomcat not load the class which is once loaded.

But the issue is Application is still slow for the first hit because the first hit has to load the classes.


So the issue is why Tomcat is so slow to load a class from a jar file.
I debug into this too.
So when we need a class, we give the path of the jar to read a class from this jar, but the RandomAccessFile.java#read method is called for every jar available in the lib folder. eg: if we have 250 jars in the Lib folder and we need one particular class,
Comment 1 Mark Thomas 2019-08-13 15:09:00 UTC
There are various odd things about this report.

The visualVM trace shows org.apache.velocity.app.event.EventCartridge.addEventHandler() calling WebappClassLoaderBase.loadClass() but there are no direct calls to loadClass() in addEventHandler() and nothing I can see that should trigger class loading.

For an increase in the TTL to improve class loading performance, the same class would have to be being loaded repeatedly. However, the class loader caches all loaded classes for the lifetime of the class loader. That suggests the class that is being requested isn't being found.

This should be followed up on the users mailing list to get to the root cause of the performance issues here. It looks like the application is repeatedly trying to load a class that does not exist.

In Tomcat 7 the web application class loader maintains a LRU cache of "not found" resources. This was removed in the resources refactoring in 8.0.x. Depending on what the further investigation on the users list finds, there might be a case for restoring that in some form.