Freemarker Template Caching - Analyzing a Struts2 Performance Problem - codecentric ...

:

During the load tests of a project I noticed the overall response time going down rapidly when more and more users were accessing the application. The application was built using the Struts 2 Java framework, accessing the database via Hibernate. It was quite a simple application, so I was wondering why it was going down so fast. When looking at the AppDynamics monitoring, I realized quickly, that there has to be an issue with Freemarker, the templating engine you can use in Struts2:

All hot spots originate from freemarker.cache.URLTemplateLoader.getURL() which is the abstract definition of a method implemented by the Struts org.apache.struts2.views.freemarker.StrutsClassTemplateLoader.

Lets debug further and find out why this code is hanging: AppDynamics collected a few thread dumps for us, which reveal a few blocked threads on sun.misc.URLClassPath.getLoader().


Looking at the source code, this is synchronized on the URLClassPath instance.

private synchronized Loader getLoader(int index) {

I did not expect this to be a bottleneck, but it turned out that there are additional threads holding/wanting this lock for classloading. This however was paused by native code for memory allocation.

There is nothing wrong with the Freemarker/Struts way of loading the templates, however it does seem to create a lot of unnecessary access to resources.

Usually templates do not change often, so it would be great if there was some kind of caching facility. And indeed Freemarker offers something:

template_update_delay=60000

This is a setting you can pipe through a struts file called freemarker.properties into the freemarker engine. According to the documentation, this takes a number of seconds a template has to be in the cache before it will be reloaded. So one should set this to a high value.

Struts folks also advise you to set a property called struts.freemarker.templatesCache to true, as they claim that the last modification cannot be obtained in a stable manner from the class path. However, as the last modification already worked well for my tested modern JDKs, I doubt this will bring further improvement.

Using the template_update_delay worked for the project, so I am fine with that, yet I still wonder why there should be a need at all to reload the files. Ok, if you hot-hack them, you need to reload them, but on real production systems, you should load them once. There is quite some code in freemarker.cache.TemplateCache which would not be required then.

While you are at tuning the Freemarker related code, you might want to provide a custom implementation of the class  org.apache.struts2.views.freemarker.FreemarkerManager, which is the connection between Struts2 and Freemarker. On closer look, it reveals to you that it tries to load the template twice from the file system before resorting to the classpath. This gives you some flexibility when developing your application, but comes with a price you might not want to pay.

After changing the “cache” setting, the HotSpots disappeared which gave the application more room to breathe. Classloader became a much less contested resource.