In this series of articles, Leonardo Uribe discusses JSF 2 and MyFaces Core performance, and its implications for web applications. Additionally, he highlights last year's (2011-2012) performance enhancements in the Apache MyFaces JSF Implementation through an in-depth comparison between JSF and Apache Wicket. Leonardo compares different aspects—speed, memory usage, session size—to give a better understanding of how JSF works under different conditions. Finally, he does an up to date (2013) web framework comparison between JSF 2 and other alternatives like Apache Wicket, Apache Tapestry, Spring MVC and Grails 2. In the end, choosing a web framework requires that you balance performance with other considerations.

In the first article, we looked at the sample application used in the performance comparison, the necessary steps to setup and run it, and how to run some JMeter scripts using Ant. Then we used the sample application to analyze JSF 2.0 from the speed perspective. In the second article of this series we'll use the sample application to analyze JSF 2.0 in different situations where memory consumption and session size become relevant. We'll examine how memory behaves under different situations and how it can impact the performance of JSF. Then we'll examine how session size is affected by JSF and its implications in web applications.

Memory

It is important to keep memory allocation to a minimum because:

Allocating memory takes time. Each call to the garbage collector (GC) is expensive and in the end slows down the web server.

To see how memory is used, I ran the following experiment with a profiler attached to see how many objects are created. Here are the experiment parameters:

CONFIGURATION Processor: AMD Phenom x4 Speed: 2300 MHz Server: Apache Tomcat 7.0.26 JVM version : oracle jdk1.6.0_30 JVM Options : -Xms128m -Xmx128 -server WARMUP loop.count: 20 thread.count: 5 include.logout : 1 include.delete: 1 booking.count: 1 include.ajax: 1 thread.delay: 0 thread.deviation: 0 rampup time: 1s EXPERIMENT loop.count: 20 thread.count: 5 include.logout : 1 include.delete: 1 booking.count: 1 include.ajax: 1 thread.delay: 0 thread.deviation:0 rampup time: 1s

Here are the results:

In this case, MyFaces used a lot less memory to do the same task, and the memory used between Mojarra and Wicket 1.4.20 is more or less the same. Wicket disk storage requires more memory than session storage, because the pages need to be saved and restored from disk. Wicket 1.5.5 uses more memory, but it is interesting that there is no significant difference between disk storage and session storage.

The integration between Facelets and JSF has made it possible to introduce some changes in the MyFaces code to reuse memory in a efficient way and minimize object allocation and collection. The idea is to reuse the information that is shared across multiple "views" and use a thin layer to create the component tree. After all, a UIComponent instance is just an object, like a String or an Iterator, so in the end, there are other details that have more weight in memory consumption.

From a memory perspective, MyFaces is the winner, but note that allocating more or less memory doesn't say much because part of this allocated memory could have a short life. However it is relevant if the web server doesn't have a lot of memory. In short, the less bytes and objects allocated the better.

To see how this effect impacts performance, a simple experiment was done:

CONFIGURATION Processor: AMD Phenom x4 Speed: 2300 MHz Server: Apache Tomcat 7.0.26 JVM version : oracle jdk1.6.0_30 JVM Options : -Xms32m -Xmx32m -server WARMUP loop.count: 200 thread.count: 40 include.logout : 1 include.delete: 1 booking.count: 1 include.ajax: 1 thread.delay: 20 thread.deviation: 10 rampup time: 1s Http Request Client : Httpclient4 EXPERIMENT loop.count: 1000 thread.count: 40 include.logout : 1 include.delete: 1 booking.count: 1 include.ajax: 1 thread.delay: 0 thread.deviation:0 rampup time: 1s Http Request Client : Httpclient4

The idea was to just reduce the memory to the minimum possible level and increase the thread count to 40, which is more than enough to fill the memory and trigger the GC frequently. In this case only MyFaces 2.1.7, Wicket 1.4.20 using session storage, and Wicket 1.5.5 were considered, because the other ones will just give some values in between. For this test, the NetBeans Profiler was attached to the server and here are the results. The following figures show the surviving generations and relative time spent in GC for 40 threads and 1000 loops in the booking application for MyFaces and two versions of Wicket.

MyFaces 2.1.7, Memory (GC) -- Time spent: 5 min 19 sec.

Wicket 1.4.20 using session storage, Memory (GC) -- Time spent: 6 min 37 sec.

Wicket 1.5.5 using disk storage, Memory (GC) -- Time spent: 16 min 39 sec.

As expected, MyFaces does very well in this comparison because it uses less memory and allocates fewer objects. It only takes 5 min 19 sec to complete the task against Wicket 1.4.20 using session storage, which takes 6 min 37 sec, while Wicket 1.5.5 takes 16 min 39 sec.

Session Size

The last factor to take into account is how the session size is affected by the web framework. In other words, the idea is to check how much overhead a web framework imposes over session storage. This could have different implications like:

If the session size is big, and it is stored in memory only, it is possible to exhaust the available memory, and it will limit the number of concurrent users for your system.

If the session size is big, and a persistence solution is used to store session information in some centralized place or share between servers (like in a cluster for example), more CPU is used because it will take longer to serialize/deserialize and transmit the necessary information across servers.

The final results will vary according to your particular deployment configuration, but of course keeping a small session size is better.

To understand more clearly why it is important, imagine this situation. You have a server with enough RAM and CPU power. Suppose the application does not use session scope at all. The limit in terms of how many requests the server can handle will be related to the processor speed. Now imagine you add some data to the server session. In this case, the limit will still be related to the processor speed, but only to the point when the session size per user reaches a specific limit and fills the available memory. After that point, it is the session size per user that imposes a limit, but there are things you can do like set a session timeout, or set client side state saving, and so on.

Here we have a balance between memory and CPU consumption. Using server side state saving and storing the necessary information in the session increases the RAM used, but sending session information to the client increases CPU consumption and network traffic, which is also inconvenient. The trick is to find a way to send only the necessary information to the client or store it into the session. The following graph shows the retained size in memory per session for the booking application.

The previous graph shows how slowly the state for JSF grows, and how quickly Wicket page storage grows, because it needs to store the whole page in the state. Even if it is necessary to store a lot of views, the session size stays very low for MyFaces, which means no matter how complex the views, only the necessary data will be stored. The next graph shows the maximum retained session size [bytes] in memory per user for the booking application.

One of the biggest improvements in MyFaces has been the changes related to Partial State Saving algorithm (PSS). The algorithm has been carefully designed to ensure zero or minimal state size, even in cases using composite components or dynamic includes.

According to the state saving mode used, it is possible to see different effects. With server side state saving, in most cases the information stored into the session by the web application will have a lot more weight over session size than the information stored by MyFaces. In client side state saving, the encoded state sent to the client will be smaller, and in that way the page size will keep smaller too.

When you consider the speed benchmark, the conclusion is PSS really is worth it. JSF takes care about all complexities involved with state handling, handling the stateless and stateful parts of the view, and in that way achieving a high performance.

Conclusion

JSF 2.0 was a big move in the right direction. JSF session size overhead is significantly lower than Wicket. MyFaces Core 2.1.7 looks very good from a performance perspective against a web framework like Wicket. In the end, MyFaces provides the better trade-off between CPU usage and session size. Wicket's bet on disk storage is good, but the JSF bet on partial state is even better. MyFaces also provides the lowest memory usage, which allows it to perform better in environments with limited CPU and memory.

With all these improvements, MyFaces is providing a JSF implementation "ready for the cloud," providing a good balance between performance and functionality. Since JSF is a standard, the only thing you need to enjoy these improvements is to use MyFaces Core as your JSF implementation. In practice, the JSF component library used will only have an effect on the render response time.

Please note the graphs presented cannot be generalized and they depend strongly on the test application, but they are the best indication available at the moment. The test application uses Ajax to update the view. It has a typical login/logout case, some datatables, and a wizard-like use case.

This is not the end of the story. Web frameworks will keep improving and the hope is this information can be useful to find new ways to enhance them (community over code is the Apache way). Performance is just one aspect that you have to consider when choosing a web framework; usually it is necessary to strike a balance between it and several other aspects.