Way2Java

Servlets JSP Performance Tuning Tips

Servlets JSP Performance

The following pages describe performance-tuning techniques (PTT) for developing high performance and scalable JSP (JavaServer Pages) pages and servlets. This means building applications that are reasonably and consistently fair.

1. Use the HttpServlet init() method for caching data

The server calls the servlet’s init() method after the server constructs the servlet instance and before the servlet handles any requests. It is called only once in a servlet’s lifetime. init() can be used to improve performance by caching the static data and/or completing the expensive operations that need to be performed only during initialization.

For example, it is a best practice to use JDBC (Java Database Connectivity) connection pooling, which involves the use of the javax.sql.DataSource interface. DataSource is obtained from the JNDI (Java Naming and Directory Interface) tree. Performing the JNDI lookup for DataSource for every SQL call is expensive and severely affects an application’s performance. Servlet’s init() method should be used to acquire DataSource and cache it for later reuse:

public class ControllerServlet extends HttpServlet
{
  private javax.sql.DataSource testDS = null;
  public void init(ServletConfig config) throws ServletException
  {
    super.init(config);   
    Context ctx  = null;
    try
    { 
      ctx = new InitialContext();
      testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");
    }
    catch(NamingException ne)
    {
      ne.printStackTrace();              
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
   }
   public javax.sql.DataSource getTestDS()
   {
     return testDS;
   }
   ...
   ...   
}

1.1 Another functionality (Use init() for static data)

Servlet is loaded into the memory by Servlet Engine (container) and calls init() method on first request and then onwards only service() method is called for every other request by creating a separate thread for each request and finally destroy() method is called when the Servlet is removed by the Servlet Engine.

The default mechanism of a Servlet Engine is to load a Servlet in multithreaded environment. In this environment, a Servlet init() method is called only once in its life time. You can improve performance using init() method. You can use this method to cache static data.

Generally a Servlet generates dynamic data and static data. Programmers often make a mistake by creating both dynamic and static data from service() method. Obviously there is a reason to create dynamic data because of its nature but there is no need to create static data every time for every request in service() method. For example, normally you would write a Servlet like this

public void service(HttpServletRequest req, HttpServletRespnse res) throws ServletException,IOException 
{
  res.setContentType(“text/html”);
  Printwriter out = req.getWriter();
  out.print("”);
  out.print("Hello world”);
  out.print(“”);
                                     // send the dynamic data here
  out.print(“”);
  out.print("”);
}

Here you are generating both static data and dynamic data. Instead you can modify the code as shown below

public class servlet extends HttpServlet 
{
  byte[] header;     
  byte[] navbar;     
  byte[] footer;   
  byte[] otherStaticData;

  public void init(ServletConfig config) throws ServletException
  {                          //create all the static data here
    StringBuffer sb = new StringBuffer(); // better to initialize the 				        
                             // StringBuffer with some size to improve performance
    sb.append("”);
    sb.append("Hello world”);
    sb.append(“”);
    
    header = sb.toString().getBytes();
			     // do same for navbar if its data is static
			     // do same for footer if its data is static
}
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException 
{
  res.setContentType("text/html");
  ServletOutputStream out = res.getOutputStream();
  out.write(header);
  out.write(navbar);                                
 				// write dynamic data here
  out.write(footer);
}

Here the static data is created in init() method which means that it is created only once in the life time of Servlet and it is used in service() method to pass the data to the client. When you send a large amount of static data, then you can use this technique to see a considerable increase in performance.

2. Optimization techniques in service() method

When you write a service() method for your Servlet, you can improve performance by using following techniques.

1. Use StringBuffer rather than using + operator when you concatenate multiple strings
2. Use print() method instead of println() method
3. Use ServletOutputStream instead of PrintWriter
4. Initialize the PrintWriter with proper size
5. Flush the data partly
6. Minimize the amount of code in the synchronized block
7. Set the content length

3. Optimization techniques in destroy() method

The destroy() method is called only once in its servlet life time when the Servlet Engine removes from memory. It is always better to remove instance variable resources such as JDBC connections, sockets and other physical resources in this method. to avoid memory leaks.


4. Cache the static and dynamic data

The use of caching in different areas of your application gives very good performance. Generally every application’s database schema will have at least some read only tables. There is no need of accessing these tables every time. You can cache that data in memory and reuse it instead of accessing database every time. It reduces network traffic, consumes less CPU cycles and gives good performance.

Caching can be done in three flavors namely static data caching, semi dynamic data caching and dynamic caching. Static data means that the data doesn’t change in its life time, it always constant. Semi dynamic data means that the data changes but not often. For example, the data that changes after every one hour can be called as semi dynamic data, the data does not change for every request. Dynamic data means that it changes the data for every request. Often people use the word dynamic data for semi dynamic data as well. So even I followed the same terminology. In this section, dynamic data is synonymous with semi dynamic data.

It is best to cache static data and dynamic data in order to improve performance. We will discuss a few caching techniques to improve Servlets JSP Performance. They are as follows.

1. Utilizing Browser caching
2. Caching dynamic data at the server
3. Utilizing application server caching facilities
4. Utilizing Servlet API’s built in facility, HttpSession and ServletContext objects

As we saw above, Caching at init() method is useful for caching static data and it reduces the creation time of static data for every request but any way finally we are passing data to the client on every request. This type of caching is useful when you want to pass both static data and dynamic data to the client. One more caching technique is utilizing the browser cache and also cache the content at the server, this can be done by avoiding a call to service() method if the output content is not changed. This technique is achieved by implementing getLastModified() method of HttpServlet class.

Web servers send the response with a ‘Last-Modified‘ header which tells the client when the page was last changed. Web browser sends a request with ‘If-Modified-Since‘ header which tells web server when it last downloaded the page. With this communication server can predict whether the file has changed or not, if not it sends response with ‘Not Modified’ (of 304 status code) so that the browser uses its cache page instead of downloading fresh page. In order to take advantage of this technique, Servlet should implement the getLastModified() method to tell the servlet engine about last modified time. This method returns time in milliseconds.

The third technique is that your application server may support caching facility for dynamic data. All you need to do is that configure the caching properties file which is supported by your server. You can give what Servlet you need to cache and session time out value to remove cache content. For example WebSphere application server supports this type of facility.

The fourth technique is that you can use Servlet API’s HttpSession and ServletContext objects for caching. HttpSession object is available for a user session across multiple requests and ServletContext object is available for all the users using the application. You can set cacheable objects into these objects and get those objects whenever you require within their scope. The methods that support caching are:

	ServletContext.setAttribute(String name, Object cacheableObject);
	ServletContext.getAttribute(String name);
	
	HttpSession.setAttribute(String name, Object cacheableObject);
	HttpSession.getAttribute(String name);


5. Choosing the right session mechanism

We use session mechanism to maintain client state across multiple pages. The session starts when the client, such as browser requests for a URL from the web server and it ends when the web server ends the session or web server times out the session or user logs out or user closes the browser.

There are few approaches available to maintain the session. They are:

1. HttpSession provided by Servlet API
2. Hidden fields
3. Cookies
4. URL rewriting
5. Persistent mechanism

Obviously it is difficult to select one mechanism out of above mentioned approaches to maintain session data. Each one impacts performance depending on amount of the data to be stored as session data and number of concurrent users.

The following table gives you an idea of performance based on the approach used.

Session mechanism Performance Description
HttpSession Good There is no limit on size of keeping session data
Hidden fields Moderate There is no limit on size of passing session data
Cookies Moderate There is a limit for cookie size
URL rewriting Moderate There is a limit for URL rewriting
Persistent mechanism moderate to poor There is no limit of keeping session data

Here the Persistent mechanism means that you store the session data in the database, file storage or any other persistent storage. There are few a approaches for this mechanism, they are

1. Using your application server’s persistent mechanism for session data storage
2. Using your own persistent mechanism by maintaining your own database schema

If you use the first approach, generally application server converts the session objects into BLOB data type and stores in the database. If you use second approach, you need to design the schema as per your session fields and need to store the session data by writing JDBC code for that, this gives better performance than the first approach because conversion of session object to BLOB takes more time than directly storing session data. Either of persistent mechanisms give moderate to poor performance when compared to other approaches because of overhead involved in database calls through JDBC and it makes calls to database on every request in order to store that session data and finally it needs to retrieve the whole session data from database but it scales well on increasing session data and concurrent users.

URL rewriting gives moderate performance because the data has to pass between the client and server for every request but there is a limitation on amount of data that can be passed through URL rewriting. It gives moderate performance because of overhead involved in network for passing data on every request.

Cookies also give moderate performance because they need to pass the session data between client and server. It also has the size limit of 4k for each cookie.

Like URL rewriting and Cookies, Hidden fields need to pass the data between client and server. All these three session mechanisms give moderate performance and is inversely proportional to the amount of session data.

HttpSession mechanism gives better Servlets JSP Performance when compared to other mechanisms because it stores the session data in memory and reduces overhead on network. Only session id will be passed between client and the server. But it does not scale well when the session data is huge and the concurrent number of users are more because of increase in memory overhead and also increase in overhead on garbage collection.

Remember that choosing the session mechanism from one of the above approaches is not only depends on performance, scalability and security. The best approach is to maintain a balance between performance, security and scalability by choosing a mixed approach. Mixture of HttpSession mechanism and Hidden fields gives both performance and scalability. By putting secure data in HttpSession and non secure data on hidden fields you can achieve better security.

6. Control HttpSession(servlets)

If you decided to use HttpSession for your session tracking, then you need to know how your application server/servlet engine implements HttpSession mechanism. You need to take care of the following points.

1. Remove session explicitly
2. Set Session time out value
3. Application server/servelt engine implementation

Generally, your application server/servlet engine will have default session time out value as 30 minutes which means that if you don’t remove session or manipulate that session for 30 minutes then your servlet engine removes that session from memory. If you set long session time out value such as 1 hour, then it keeps all the session objects till 1 hour. This approach effects scalability and performance because of overhead on memory and garbage collection. In order to reduce memory overhead and to increase performance, it is better to remove/invalidate session explicitly using HttpSession.invalidate() method and also try to reduce the session time out value as per your application’s requirement.

Third important point is that your application server may serialize session objects after crossing certain memory limit; it is expensive and effects Servlets JSP Performance because it not only serializes the single session object but also serializes the total object hierarchy. Use ‘transient’ for variables to avoid unnecessary serialization. So know about your application server/servlet engine session implementation mechanism and act accordingly.

7. Disable Servlet auto reloading

Most of the application servers/servlet engines have the capability of loading servlets dynamically, which means you need not restart your server whenever you change the servlet content. Application server/servlet engine loads the servlet with auto reload each time when you configure the servlet. For example, if you configure auto reload as 1 second, then servlet engine loads that servlet after every 1 second. This feature is good at development time because it reduces the development time by avoiding restarting the server after every change in servlet. But it gives poor Servlets JSP Performance at production by unnecessary servlet loading and burden on class loader. So turn off your auto reloading feature in the configuration file to improve performance.

8. Control Thread pool
Servlet engine creates a separate thread for every request and assigns that thread to service() method in its multithreaded servlet and finally it removes that thread after completion of service() method execution. It happens for every request. Your servlet engine may create a new thread for every request by default. This default behavior reduces performance because creating and removing threads is expensive. This can be avoided by using the thread pool. Servlet engine creates pool of threads at start up and assigns a thread from pool to every request instead of creating a fresh thread every time and it returns that thread to the pool after completion. The size of the thread pool depends upon configuration parameters of the pool. The pool will have minimum and maximum number of threads and you can configure these numbers in the configuration file of your servlet engine. The number of maximum and minimum threads in pool depends upon concurrent users for your application. You have to estimate number of concurrent users for your application and give the thread pool size based on that. Obviously there is a limit on thread pool which depends on your hardware resources. By setting thread pool size correctly, the performance of servlet improves significantly. Your application server/ JSP engine may not have facility to configure thread pool. Tomcat’s Servlet Engine has the facility to configure thread pool. Look at your application server / servlet engine documentation for information about thread pool.


9. Control HttpSession(JSP)

Many applications require a series of client requests so they can associate with one another. Web-based applications are responsible for maintaining such state, called a session, because the HTTP protocol is stateless. To support applications that must maintain state, Java servlet technology provides an API for managing sessions and allows several mechanisms for implementing sessions. Sessions are represented by an HttpSession object, but a cost is involved while using it. An HttpSession must be read by the servlet whenever it is used and rewritten when it is updated. You can improve performance by applying the following techniques:

1. Do not create HttpSessions in JSP pages by default: By default, JSP pages create HttpSessions. If you do not use HttpSession in your JSP pages, to save some performance overhead, use the following page directive to prevent HttpSessions from being created automatically when they are unnecessary in JSP pages:

<%@ page session="false"%>

2. Do not store large object graphs inside an HttpSession: If you store the data in the HttpSession as one large object graph, the application server will have to process the entire HttpSession object each time. This forces Java serialization and adds computational overhead. The throughput decreases as the size of the objects stored in the HttpSession increases because of the serialization cost.

3. Release HttpSessions when done: Invalidate sessions when they are no longer needed using the HttpSession.invalidate() method.

4. Set session time-out value: A servlet engine has a default session time-out value set. If you do not either remove the session or use it for the time equal to the session time-out, the servlet engine will remove the session from memory. The larger the session time-out value, the more it affects scalability and performance because of overhead on memory and garbage collection. Try to keep the session time-out value as low as possible.

10. Use gzip compression

Compression is the act of removing redundant information, representing what you want in as little possible space. Using gzip (GNU zip) to compress the document can dramatically reduce download times for HTML files. The smaller your information’s size, the faster it can all be sent. Therefore, if you compress the content your Web application generates, it will get to a user faster and appear to display on the user’s screen faster. Not every browser supports gzip compression, but you can easily check whether a browser supports it and then send gzip-compressed content to only those browsers that do.

Here is the code snippet that shows how to send compressed content whenever possible:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException 
{
  OutputStream out = null

	   // Check the Accepting-Encoding header from the HTTP request.
  	   // If the header includes gzip, choose GZIP.
   	   // If the header includes compress, choose ZIP.
                  // Otherwise choose no compression.

  String encoding = request.getHeader("Accept-Encoding");    
      
  if (encoding != null && encoding.indexOf("gzip") != -1)
  {
    response.setHeader("Content-Encoding" , "gzip");
    out = new GZIPOutputStream(response.getOutputStream());
  }
  else if (encoding != null && encoding.indexOf("compress") != -1)
  {
    response.setHeader("Content-Encoding" , "compress");
    out = new ZIPOutputStream(response.getOutputStream());
  } 
  else
  {
    out = response.getOutputStream();
  }
   ...
   ...                        
}  

11. Do not use SingleThreadModel

SingleThreadModel ensures that servlets handle only one request at a time. If a servlet implements this interface, the servlet engine will create separate servlet instances for each new request, which will cause a great amount of system overhead. If you need to solve thread safety issues, use other means instead of implementing this interface. SingleThreadModel interface is deprecated in Servlet 2.4.

12. Choose the right include mechanism

There are two ways you can include files in a JSP page: include directive (<%@ include file="test.jsp" %>) and include action (). The include directive includes the specified file’s content during the translation phase; i.e., when the page converts to a servlet. The include action includes the file’s content during the request processing phase; i.e., when a user requests the page. Include directive is faster than include action. So unless the included file changes often, use include directive for better performance.

13. Choose the right scope in useBean action

One of the most powerful ways to use JSP pages is in cooperation with a JavaBeans component. JavaBeans can be directly embedded in a JSP page using the action tag. The syntax is as follows:



The scope attribute specifies the scope of the bean’s visibility. The default value for scope attribute is page. You should select the correct scope based on your application’s requirements, otherwise it will affect application performance.

For example, if you need an object only for a particular request, but your scope is set to session, that object will remain in memory even after you are done with the request. It will stay in memory until you explicitly remove it from memory, you invalidate the session, or the session times out as per the session time-out value configured with the servlet engine. If you do not select the right scope attribute value, it will affect the performance because of overhead on memory and garbage collection. So set the exact scope value for the objects and remove them immediately when finished with them.

14. Miscellaneous techniques

1. Avoid string concatenation: The use of the + operator to concatenate strings results in the creation of many temporary objects because strings are immutable objects. The more you use +, the more temporary objects are created, which will adversely affect performance. Use StringBuffer instead of + when you concatenate multiple strings.

2. Avoid the use of System.out.println: System.out.println synchronizes processing for the duration of disk I/O, and that can slow throughput significantly. As much as possible, avoid the use of System.out.println. Even though sophisticated debugging tools are available, sometimes System.out.println remains useful for tracing purpose, or for error and debugging situations. You should configure System.out.println so it turns on during error and debugging situations only. Do that by using a final boolean variable, which, when configured to false, optimizes out both the check and execution of the tracing at compile time.

3. ServletOutputStream versus PrintWriter: Using PrintWriter involves small overhead because it is meant for character output stream and encodes data to bytes. So PrintWriter should be used to ensure all character-set conversions are done correctly. On the other hand, use ServletOutputStream when you know that your servlet returns only binary data, thus you can eliminate the character-set conversion overhead as the servlet container does not encode the binary data.

4. Avoid the unnecessary creation of objects: This has always been good advice–creating unnecessary objects wastes memory and wastes a fair amount of time as the objects are created. With servlets, it’s even better advice. All but the most recent JVMs have a global object heap that must be locked for each new memory allocation. While any servlet is creating a new object or allocating additional memory, no other servlet can do so.