https://bz.apache.org/bugzilla/show_bug.cgi?id=63685
Bug ID: 63685 Summary: WebappClassLoaderBase and StandardRoot reload classes from jar files on each call of getResource, getResourceAsStream and etc. that hit application startup performance Product: Tomcat 8 Version: 8.5.x-trunk Hardware: All OS: All Status: NEW Severity: normal Priority: P2 Component: Catalina Assignee: dev@tomcat.apache.org Reporter: cheglov.alexa...@gmail.com Target Milestone: ---- During profiling of the application I found interesting behavior related to class loading and caching in org.apache.catalina.loader.WebappClassLoaderBase and org.apache.catalina.webresources.StandardRoot. Situation. I have very big Spring application which consists of a bit more than 1500 jar files. Startup of this application takes quite a lot of time. After investigation with logs analysis, profiling and debugging including Tomcat source code it was found out that one of the reasons is laid in Tomcat classloading behavior. A lot of methods of Tomcat's org.apache.catalina.loader.WebappClassLoaderBase calls for org.apache.catalina.WebResourceRoot#getClassLoaderResource(String path), for example: - public URL getResource(String name); - public URL findResource(final String name); - public InputStream getResourceAsStream(String name). Every time as one of these methods is invoked for .class files it leads to invocation of org.apache.catalina.webresources.StandardRoot#getResourceInternal(String path, boolean useClassLoaderResources) method, which searches for the class file across all the jars in application WEB-INF\lib directory. And in my case it's about 1500 jar files. In org.apache.catalina.webresources.StandardRoot already there is cache for WebResources. But currently it's used for static content only. There is special check with comment in org.apache.catalina.webresources.Cache.class: private boolean noCache(String path) { // Don't cache classes. The class loader handles this. // Don't cache JARs. The ResourceSet handles this. if ((path.endsWith(".class") && (path.startsWith("/WEB-INF/classes/") || path.startsWith("/WEB-INF/lib/"))) || (path.startsWith("/WEB-INF/lib/") && path.endsWith(".jar"))) { return true; } return false; } Comment tells that classes cache is handled by class loader, but in fact classloader caches only instances of the created classes, but not the content of the .class files or their URLs. After modification of the noCache method as below: private boolean noCache(String path) { // Don't cache JARs. The ResourceSet handles this. return (path.startsWith("/WEB-INF/lib/") && path.endsWith(".jar")); } and setting cacheMaxSize and cacheTtl parameters, time of application startup was reduced in average about 5 minutes. I understand that it's not an issue for a small application, but as we see from the result in case of a huge application it can give noticeable speedup of application launch. In my case I faced with performance problem mainly in case of application startup but theoretically this behavior can bring negative impact on work of application in runtime as well. Would you be so kind to let me know why classes cache was intentionally skipped in org.apache.catalina.webresources.Cache.class and if it's possible to enable it and promote such fix? Or if it's a bad idea what are the potential drawbacks I can face if I decide to enable cache of classes in Tomcat for my application? Thank you! -- You are receiving this mail because: You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org