Damodar's Musings

web development and miscellany

Browsing Posts in Java

All right – now, we’re finally ready to get to the meat of what JSR 315 brings to the table – asynchronous servlets.

Prior to JSR 315, the world was a very simple and pleasant place. It was the world of the synchronous web. The server maintained a server socket that waited at the gates for weary incoming requests, and as each one arrived, assigned a worker to help it accomplish its needs. In this model, there was a finite set of workers (or server threads), and once all available workers were busy, new incoming requests had to wait at the gate until a worker completed processing its current request.

The process of setting up and tearing down socket connections is an expensive operation, and the process of TCP bandwidth throttling means that the earlier transmissions over a new connection are slower than later ones. As a result, HTTP 1.1 introduced its keep-alive connection model, which allowed a client to hold the connection open (i.e. to have a worker thread assigned) until all resources on a given page were retrieved.

This model works very well, and is both very performant and scalable, since requests come in at staggered intervals, allowing a small thread pool to successfully handle a large volume of client requests.

However, all was not well in the good old days.

First, was the issue of thread starvation. Each thread consumes server side resources – both memory and CPU resources. As a result, the number of threads within the pool must be constrained to some finite number. Furthermore, if the processing that the thread must perform for a client requires some blocking operation (say waiting on some slow external resource such as a database or web service), that thread is effectively unavailable to the server. In other words, it is possible that all threads in the pool are soon blocked and incoming requests can no longer be effectively handled. This is not just a theoretical problem. With the prevalence of fine grained Ajax-requests, and the adoption of SOA, the load on web servers is on an upward trend.

Second was the issue of staleness. At any given point, a client gets a view of the web application’s state at the instant that the request was procesed. Any changes to state between two consecutive requests from a client, are effectively invisible to that client. In other words, each client only gets a static snapshot view into what is effectively a dynamic system. And the currency of that view decays the longer the time period between requests. Ajax’s fine grained interactions, do mitigate this problem, but it does not completely solve the currency issue.

Third was the issue of non standard implementations. The developers of every servlet container decided to solve this problem of the synchronous web by implementing their own custom solutions. Tomcat’s Comet, WebLogic’s FutureResponseServlet, and WebSphere’s Asynchronous Request Dispatcher are examples of developers not wanting to wait for the standards  body to catch up.

A key piece of JSR 315 therefore was to solve these issues with the synchronous web, by introducing us to the asynchronous web.

The problem of thread starvation is solved by having the main request processing worker thread delegate processing to an asynchronous thread, and return to the thread pool. In other words, if processing will require blocking operations, the worker can put the request processing context on ice, and hand it off to an asynchronous thread for processing. It can then return to the thread pool and wait for the next incoming request.

The problem of staleness is solved by allowing the client to make preemptive requests. I.e., just as soon as the client receives a snapshot, it can turn around and immediately make a preemptive request for the next snapshot. This request can be handed off to an asynchronous processor on the server, which will be notified when a state change occurs, and can immediately return a response to the waiting client. As far as the client is concerned, this looks just like any other long running request. Of course, with the advantage that there’s hardly a lag between a server side state change, and a client notification.

Finally, this solves the standardization issue by codifying asynchronous behavior into the servlet specification. This is now the one approach to rule them all!

So what do we need to implement asynchronous servlets?

  • Thread Pool and Queue
    If you haven’t read my previous blog post on thread pools in Java, this is the time to go do so. An Executor and ExecutorService provide us with a mechanism to implement our pool of asynchronous workers.
  • AsyncContext
    The context of the request must be stored for later use by the asynchronous worker thread. This is achieved using an AsyncContext instance, which holds the request and response that was provided by the container to the original servlet.
  • Runnable instance
    This instance encapsulates the actual processing of the blocking operation on the asynchronous thread.
  • Servlet/Filter chain
    All components that will participate in an asynchronous request must be marked as supporting asynchronous operation.

Let’s walk through the recipe of creating an asynchronous servlet:

  1. At context startup, a context listener is used to set up an Executor.
  2. Servlets that might involve a blocking operation are identified and marked as asyncSupported (annotation or web.xml declaration). Any servlets/filters in the processing chain for this servlet are similarly marked.
  3. Within its service() method, the asynchronous servlet then:
    1. Invokes startAsync() on the request
    2. Wraps the returned AsyncContext in a Runnable
    3. Hands the Runnable off to an Executor for asynchronous processing
    4. Returns from the service() method. For an asynchronous servlet, returning from this method does not automatically commit the response. As a result, the client has no idea that it is being given the run around – it patiently waits for the response.
  4. The main thread returns to the server’s pool, ready to handle the next incoming request.
  5. The Executor assigns an async thread to process the Runnable.
  6. The Runnable:
    1. Uses the request and response stored in its AsyncContext
    2. Accesses any request attributes/parameters that are stored in its request to perform its processing
    3. Stores the final result of the processing as a request attribute
    4. “Completes” the response – either by generating the response by itself, or by dispatching to a server side resource.
  7. The client now displays the resource.

To the client, this interaction is no different from a slow server taking an inordinate amount of time to respond.

To the server, the server worker thread spent only a fraction of the time it would have normally taken to handle such a request, helping its throughput significantly.

The actual processing was handled by a thread in a separate pool – without impacting the main server pool.

The servlet context listener does nothing more than set up a ThreadPoolExecutor with 10 threads, and a request queue with a limit of 100 pending requests.

package com.swengsol.listeners;
/**
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 10:48:14 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import java.util.EnumSet;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

@WebListener
public class MyServletContextListener implements ServletContextListener {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    // Public constructor is required by servlet spec
    public MyServletContextListener() {
    }

    // -------------------------------------------------------
    // ServletContextListener implementation
    // -------------------------------------------------------
    public void contextInitialized(ServletContextEvent sce) {
        logger.info("Context Listener > Initialized");

        //2. Creation of a global async Executor
        Executor executor =
					new ThreadPoolExecutor(10, 10, 50000L,
						TimeUnit.MILLISECONDS,
						new LinkedBlockingQueue<Runnable>(100));
        sce.getServletContext().setAttribute("executor", executor);
    }

    public void contextDestroyed(ServletContextEvent sce) {
    }
}

The servlet is marked with an annotation to indicate that it supports async processing. Some key elements to note are:

1)    The presence of the dispatch parameter on the query string will allow us to control how the async request completes (whether it is handled completely by the asynchronous processor or whether it is forwarded on to another server side resource).

2)    The timeout parameter allows us to set a timeout for an asynchronous request. The request is aborted if it does not complete within the specified timeout.

3)    The call to startAsync() builds up the AsyncContext, which represents the context of the current request.

4)    An AsyncListener can be registered to be notified of events within the asynchronous process– such as timeouts.

5)    The thread pool with our async worker threads is retrieved from the servlet context, and is given an instance of our Runnable to process – an AsyncRequestProcessor.

6)    The main worker thread now returns without committing the response.

package com.swengsol.servlets;

import com.swengsol.AsyncRequestProcessor;
import com.swengsol.listeners.MyAsyncListener;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.*;
import java.util.logging.Logger;

/**
 * User: Monsty
 * Date: Jul 23, 2010
 * Time: 9:43:25 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */
@WebServlet(urlPatterns = "/AsyncServlet", asyncSupported=true)
public class AsyncServlet extends HttpServlet {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    protected void doPost(HttpServletRequest request,
			HttpServletResponse response)
		throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request,
			HttpServletResponse response)
		throws ServletException, IOException {
        logger.info("AsyncServlet: Processing request: " +
					request.getParameter("id") + ". on thread: " +
					Thread.currentThread().getId() + ":" +
					Thread.currentThread().getName() + "[" +
					new Date() + "]");

				request.setAttribute("receivedAt", new Date());

        boolean dispatch = false;
        String dispatchParam = request.getParameter("dispatch");
        if ("true".equalsIgnoreCase(dispatchParam)) dispatch = true;

        boolean timeout = false;
        String timeoutParam = request.getParameter("timeout");
        if ("true".equalsIgnoreCase(timeoutParam)) timeout = true;

        AsyncContext asyncCtx = request.startAsync();
        asyncCtx.addListener(new MyAsyncListener());
        if (timeout) {
            asyncCtx.setTimeout(1000);
        }

        Executor executor =
			(Executor)request.getServletContext().getAttribute("executor");
		//delegate long running process to an "async" thread
        executor.execute(new AsyncRequestProcessor(asyncCtx, dispatch));

        logger.info("AsyncServlet: Returning after request: " +
					request.getParameter("id") + ". on thread: " +
					Thread.currentThread().getId() + ":" +
					Thread.currentThread().getName()+ "[" +
					new Date() + "]");

				//Watch out for concurrency issues at this point
				// between the "main" thread and the "async" thread
				// main thread returns now -
				// - returning from service() does not commit the response
				// - so client still waits patiently
    }
}

The nice thing about this is that the servlet itself is pretty formulaic – and shouldn’t change much from one async servlet to the next. But all the complexity of processing has to go somewhere – and that somewhere is the AsyncRequestProcessor.

Also note the comment at the bottom of the file that indicates that there is now a short window of time here when the request and response objects are no longer thread safe. Ideally, you shouldn’t be mucking around with the request and response objects once you’ve handed them off to the async processor.

The asynchronous request processor is a Runnable instance that needs access to the AsyncContext that we previously retrieved from the request. In our example, note that the long running blocking operation is encapsulated within the longRunningProcess() method.

package com.swengsol;

import javax.servlet.AsyncContext;
import javax.servlet.ServletRequest;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 9:45:22 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */
public class AsyncRequestProcessor implements Runnable {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    private AsyncContext asyncContext;
    private boolean dispatch;
    public  AsyncRequestProcessor(AsyncContext asyncContext) {
        this.asyncContext = asyncContext;
        dispatch = true;
    }
    public AsyncRequestProcessor(AsyncContext asyncContext,
		boolean dispatch) {
        this(asyncContext);
        this.dispatch = dispatch;
    }
    public void run() {
        //do something asynchronously –
		//  wait for a resource to become available
		//  or for a long running computation to finish
        String reqId = asyncContext.getRequest().getParameter("id");
        if (null == reqId || reqId.length() == 0) reqId = "<unk>";
        long id = Thread.currentThread().getId();
        String threadName = Thread.currentThread().getName();
        if (null == threadName || threadName.length() == 0)
			threadName = "";
        String threadId = id + ":" + threadName;

        String result = longRunningProcess(reqId, threadId);

        //Store the result of the computation in a "view helper"
        ServletRequest req = asyncContext.getRequest();
        if (null != req && req.isAsyncStarted())
					req.setAttribute("result", result);
        else
					return;

        //once done, dispatch back to the final destination
        if (dispatch) {
            asyncContext.dispatch("/results.jsp");
        } else {
            //alternatively handle it ourselves
            String html = "Result of the process for request id: " +
					reqId + "<br/> Started at:" +
					asyncContext.getRequest().getAttribute("receivedAt") +
					".<br/> Completed at:" + result +
					"<br/> Called complete.";
            Squawker squawker = new Squawker(html);
            asyncContext.getResponse().setContentType("text/html");
            try {
                PrintWriter out = asyncContext.getResponse().getWriter();
                out.println(squawker.getHTML());
            } catch(Exception e) {
                logger.log(Level.WARNING, e.getMessage(), e);
            }
            asyncContext.complete();
        }
    }

    public String longRunningProcess(String reqId, String threadId) {
        Random randomGenerator = new Random();
        int randomInt = 5000 + randomGenerator.nextInt(10000);
        logger.info("AsyncRequestProcessor: Begin long run process (" +
					randomInt + " ms) for request: " +
					reqId + ". on thread: " + threadId +
					"[" + new Date() + "]");

        try {
            Thread.sleep(randomInt);
        } catch (InterruptedException ie) {
            logger.log(Level.WARNING, ie.getMessage(), ie);
        }

        logger.info("AsyncRequestProcessor: Done processing request: " +
					reqId + ". on thread: " +
					threadId + "[" + new Date() + "]");
        return new Date().toString();
    }
}

In this example, the long running process simply sleeps for a random amount of time to simulate the randomness of accessing a remote resource. It takes anywhere from 5 to 15 seconds to complete its work – an eternity on the web. You can also imagine report generation processes that might take much longer.

Once the long running process has returned, we either dispatch the request to be handled by a server side resource (results.jsp), or we handle it ourselves by handcrafting the HTML to be returned. In the latter case, we have to explicitly call complete() on the AsyncContext instance. In the former, the container does so implicitly.

The server side resource that we forward our asynchronous request to is results.jsp. This file demonstrates how request attributes added by the async processor can be retrieved and used.


<%--
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 9:45:22 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
	<head>
  	<title>Introducing Servlet 3.0</title>
    <link rel=stylesheet type="text/css"  href="styles.css">
	</head>
	<body>
		<p class="mainpara">
			results.jsp:
			completed processing of long running activity with id:
			<span style="color:#ff3300">
				<%=request.getParameter("id")%>
			</span>
			<br/>
			received  at: <%=request.getAttribute("receivedAt")%>: <br/>
			completed at: <%=request.getAttribute("result")%>
		</p>
		<p class="copyright">Damodar Chetty,
			Software Engineering Solutions, Inc.</p>
	</body>
</html>

My sample code running on GlassFish v3 did not run until I added an XML declaration for my async servlet. To me this looks like a bug in the RI.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

	version="3.0">
    <servlet>
        <servlet-name>AsyncServlet</servlet-name>
        <servlet-class>com.swengsol.servlets.AsyncServlet</servlet-class>
        <async-supported>true</async-supported>
    </servlet>
</web-app>

The final class we will visit is our AsyncListener which is rather trivial in my sample implementation. If you check your GlassFish logs, you’ll notice entries for the async listener which indicate when the async processing was completed.

package com.swengsol.listeners;
/**
 * User: Damodar Chetty
 * Date: Jul 24, 2010
 * Time: 2:36:08 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import java.util.logging.Logger;

public class MyAsyncListener implements AsyncListener {
    private static final Logger logger =
		Logger.getLogger("com.swengsol");

    // Public constructor is required by servlet spec
    public MyAsyncListener() {    }
    public void onComplete(AsyncEvent ae) {
		logger.info("AsyncListener: onComplete for request: " +
			ae.getAsyncContext().getRequest().getParameter("id"));
	}
    public void onTimeout(AsyncEvent ae) {
		logger.info("AsyncListener: onTimeout for request: " +
			ae.getAsyncContext().getRequest().getParameter("id"));
	}
    public void onError(AsyncEvent ae) {
		logger.info("AsyncListener: onError for request: " +
			ae.getAsyncContext().getRequest().getParameter("id"));
	}
    public void onStartAsync(AsyncEvent ae) {
		logger.info("AsyncListener: onStartAsync");
	}
}

This servlet can be invoked using the URL:

http://localhost:8008/jsr315/AsyncServlet?id=1&dispatch=true&timeout=false

where, jsr315 is my context path, /AsyncServlet is the URL pattern for my servlet, and the dispatch and timeout query string parameters can be used to test out alternative behaviors.

That’s all folks!

Help is at hand for everyone who has ever cursed at having to add entries to their web.xml just because they wanted to use a third party framework.

With JSR 315, web.xml is no longer a single monolithic entity, but instead can be assembled from multiple pieces (called web fragments) into a single whole.

For instance, here’s a project I rolled earlier, that is packaged as jSwengsol.jar. This external JAR file would be deployed into your web application’s WEB-INF/lib folder, and as usual, is able to contribute web components (such as servlets, filters, or listeners). In my JAR, these components live within the com.swengsol package.

Note the presence of two special entries within this JAR file, the META-INF/web-fragment.xml file and the resources directory.

The web fragment entry allows an external JAR to package the configuration of its contained web components. This fragment will be merged into your own application’s web.xml when your application is deployed into the servlet container.

The optional resources folder can contain static resources (such as HTML, CSS, and JS files) as well as dynamic resources (JSPs). Resources provided within this folder are publicly available. Note that these resources live within your web application’s WEB-INF folder,  and yet are visible to the external world. This means that frameworks no longer have to implement workarounds (such as filters mapped to URL paths) to serve up resources that are required by that framework’s components.

Note that jSwengsol.jar is deployed into our main web application’s WEB-INF/lib.

This JAR file will now be described.

The IDEA configuration for generating the JAR file is as shown:

To build this artifact, I simply use Build > Build ‘jSwengsol’ artifact:

Squawker.java is a standard helper class that is used by our main web application. It is a very simple helper that takes a message and generates the HTML scaffolding around it. An important point of note is that it retrieves the stylesheet straight out of the web application’s WEB-INF/lib/jSwengsol.jar!resources/styles.css.

package com.swengsol;
/**
* User: Damodar Chetty
* Date: Jul 23, 2010
* Time: 8:13:26 AM
* An introduction to Servlet 3.0 and Java 6 (TC JUG)
* (c) Software Engineering Solutions, Inc.
*/
public class Squawker {
	private String title;
	private String body;
	public Squawker(String body) {
		this("Introducing Servlet 3.0", body);
	}
	public Squawker(String title, String body) {
		this.title = title;
		this.body = body;
	}
	public String getHTML() {
		String html = "<html><head>";
		if (null == title || title.length() ==0)
			title = "JSR315: Servlet 3.0";
		html += "<title>" + title + "</title>";
		html +=
		"<link rel=stylesheet type=\"text/css\"  href=\"styles.css\">";
		html += "</head> <body><p>" ;
		html += body;
		html += "</p>";
		html += "<p class=\"copyright\">Damodar Chetty,”;
		html += “ Software Engineering Solutions, Inc.</p>";
		html += "</body></html>";
		return html;
	}
}

The stylesheet, styles.css, is also a very straightforward affair:

.mainpara {
	font-size: 15pt;
	font-family:'trebuchet ms';
	padding:20;
	border-color:#736AFF;
	position:absolute;
	top:50;
	left: 200;
	border-style: dotted;
}
.copyright {
	width:375px;
	font-size:12pt;
	font-weight:bold;
	font-family:serif;
	background-color:black;
	color:white;
	position: absolute;
	top:300;
	left:500;
	padding:5;
}
body {background-color:#E0FFFF; color:#7F5217;}

In addition, you can also directly request the static resource, jSwengsol.html (listed below) as if it were directly within the root of our web application context, http://localhost:8008/jsr315/jSwengsol.html, where jsr315 is the context path for the web application that includes this JAR file.

<html>
<head>
<title>Introducing Servlet 3.0</title>
<link rel=stylesheet type="text/css"  href="styles.css">
</head>
<body>
<p>This is a static resource file served up from jSwengsol.jar</p>
<p>Damodar Chetty, Software Engineering Solutions, Inc.</p>
</body>
</html>

Likewise, you can access the JSP file as http://localhost:8008/jsr315/jSwengsol.jsp:

<%@ page import="java.util.Date" %>
<%--
  Created by IntelliJ IDEA.
  User: Monsty
  Date: Jul 22, 2010
  Time: 9:24:48 PM
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head><title>Introducing Servlet 3.0</title>
  <link rel=stylesheet type="text/css"  href="styles.css">
  </head>
  <body>
    <p class="mainpara">
      jSwengsol.jar!jSwengsol.jsp says the time is now <%=new Date()%>
   </p>
    <p class="copyright">
      Damodar Chetty, Software Engineering Solutions, Inc.
    </p>
  </body>
</html>

Now, let’s take a look at the web fragment, META-INF/web-fragment.xml:

<web-fragment>
  <name>jSwengsolFragment</name>
  <listener>
    <listener-class>com.swengsol.listeners.MyServletRequestListener</listener-class>
  </listener>
</web-fragment>

Firstly, note that a fragment can be named. This comes in handy when you are trying to specify ordering rules that define how multiple fragments can be combined into the application’s web.xml. Second, note that as its name suggests, this fragment is not a complete descriptor. Here it contains only the listener’s declaration within this fragment is automatically rolled into the main web application’s web.xml.

package com.swengsol.listeners;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.logging.Logger;

//1. No annotation - uses web-fragment.xml
public class MyServletRequestListener implements ServletRequestListener {
    private static final Logger logger = Logger.getLogger("com.swengsol");
    // Public constructor is required by servlet spec
    public MyServletRequestListener() {
    }

    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        logger.info("RequestListener > request destroyed - " + new Date());
    }

    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        HttpServletRequest req =
		(HttpServletRequest)servletRequestEvent.getServletRequest();
        String uri = req.getRequestURL().toString();
        logger.info("RequestListener > request initialized - " + uri + " - "
		 + new Date());
    }
}

There’s nothing noteworthy about this listener, except to point out that I specifically avoided using an annotation here to show how a web fragment functions.

To show how annotations could have been used instead, check out the JARServlet servlet:

package com.swengsol.servlets;

import com.swengsol.Squawker;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.logging.Logger;

/**
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 1:12:21 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */
@WebServlet("/JarServlet")
public class JARServlet extends HttpServlet {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    protected void doPost(HttpServletRequest request,
			HttpServletResponse response)
        throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request,
			HttpServletResponse response)
        throws ServletException, IOException {
        logger.info("Within JARServlet request>>>" + new Date());

        Squawker squawker =
		new Squawker("Hello from jSwengsol.jar!JARServlet: " + new Date());
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println(squawker.getHTML());
    }
}

In this case, the servlet annotation is sufficient to register this servlet with the main web application, so no fragment entry is necessary.

That’s about it for now. As you can tell, there’s legs to this story – and I can imagine it being very useful as we head off into the future.

Next up is the idea of programmatic definition of components. One might argue that this is not a real benefit, and I might even agree.

For a while now, it has been vogue to decry the explicit instantiation of components – and the new operator has been driven out of its usual home, and into factory methods and abstract factories. Then there was the XML movement which decreed that everything configurable should happen within configuration files – which gave rise to a slew of deployment descriptors. The idea was sound – why should a configuration change need a compile/build and deploy? Well it seems we’re back full circle. With programmatic definition, we can once again instantiate components programmatically and then configure them.

In this example, we’ll see how you might programmatically instantiate servlets, filters, and listeners.

First, let’s revisit our servlet context listener from the last post. For brevity, I’m only showing the parts that are new.

@WebListener
public class MyServletContextListener implements ServletContextListener {
		…
    public void contextInitialized(ServletContextEvent sce) {
        logger.info("Context Listener > Initialized");
        doProgrammaticRegistration(sce.getServletContext());
    }

    private void doProgrammaticRegistration(ServletContext sc) {
        ServletRegistration.Dynamic dynamic = sc.addServlet(
					"ProgrammaticServlet",
					"com.swengsol.servlets.MyProgrammaticServlet");
        dynamic.addMapping("/ProgrammaticServlet");
        FilterRegistration.Dynamic filter = sc.addFilter(
					"MyProgrammaticFilter",
					"com.swengsol.filters.MyProgrammaticFilter");
        EnumSet<DispatcherType> disps = EnumSet.of(
					DispatcherType.REQUEST, DispatcherType.FORWARD);
        filter.addMappingForServletNames(disps, true,
					"ProgrammaticServlet");
    }
}

As shown, during context initialization, we instantiate a new servlet, and use its returned ServletRegistration.Dynamic instance to configure the appropriate mapping. We take similar steps with a filter. These steps are similar to what would have happened when a servlet container encountered the <servlet>, <servlet-mapping>, <filter>, and <filter-mapping> elements in a web deployment descriptor.

As can be seen in the next listings, the servlet and filter are rather straightforward. Since the configuration occurs programmatically, they do not even need any annotations to be used.

package com.swengsol.filters;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.logging.Logger;

/**
 * User: Monsty
 * Date: Jul 24, 2010
 * Time: 8:45:10 AM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

//1. Not even annotation is required
public class MyProgrammaticFilter implements Filter {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp,
	FilterChain chain) throws ServletException, IOException {
        logger.info("> Filtering: " +
			((HttpServletRequest)req).getRequestURI());
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {
        logger.info("> Filter: " + "Initializing ProgrammaticFilter");
	}
}

The servlet class is similarly simple. We will see the Squawker class in the next post. For now, all you need to know is that it is used to generate the HTML scaffolding around the text being displayed.

package com.swengsol.servlets;

import com.swengsol.Squawker;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.logging.Logger;

/**
 * User: Damodar Chetty
 * Date: Jul 24, 2010
 * Time: 8:46:17 AM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

//1. Note not even an annotation is required.
public class MyProgrammaticServlet extends HttpServlet {
    private static final Logger logger =
		Logger.getLogger("com.swengsol");

    protected void doPost(HttpServletRequest request,
	HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {
        logger.info("Within request>>>" + getServletName());
        Squawker squawker = new Squawker("Added programmatically " +
				"(no annotation/web.xml entries): " + new Date());
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println(squawker.getHTML());
    }
}

Simple enough?

In this series of articles, I’m going to describe elements of my talk at the TC JUG.

I chose to present the topics in JSR 315 in an ascending order of importance. So let’s begin with what i think is the least important of the lot. I’m sure others will argue with my ordering, but since this is my blog, I get to make the calls ;)

So, let’s begin with annotations.

With JSR 315, the servlet container is finally a completely optional artifact. That’s a bit of oversimplification, but it is certainly true that for the most part. The servlet container must introspect all the classes in WEB-INF/classes as well as in WEB-INF/lib/*.jar looking for annotations. You can speed up servlet container starts by preventing this scanning of classes – if you set the metadata-complete attribute to true on the web-app element of your application’s web.xml.

Let’s begin by taking a look at a filter in the new world.

First, notice that the web.xml file is simply a shadow of its former self – and could have been omitted.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

	version="3.0">
</web-app>

The filter is declared using the @WebFilter annotation and is registered as a filter for the /foo URL pattern.

package com.swengsol.filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.logging.Logger;

/**
 * User: Damodar Chetty
 * Date: Jul 24, 2010
 * Time: 8:39:20 AM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

// 1. Annotations can map to either url patterns or servlet names
@WebFilter(urlPatterns = "/foo", filterName = "MyFilter")
public class MyFilter implements Filter {
    private static final Logger logger =
		Logger.getLogger("com.swengsol");
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp,
		FilterChain chain) throws ServletException, IOException {
        logger.info("> Filtering: " +
			((HttpServletRequest)req).getRequestURI());
        chain.doFilter(req, resp);
    }
    public void init(FilterConfig config) throws ServletException {
        logger.info("> Filter: " + "Initializing filter");
    }
}

The key element to notice here is the annotation that maps the url patterns /foo and /bar to our servlet. The filter we defined earlier will be invoked only when this servlet is requested using the pattern, /foo.

package com.swengsol.servlets;

import com.swengsol.Squawker;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.logging.Logger;

/**
* User: Damodar Chetty
* Date: Jul 24, 2010
* Time: 8:26:34 AM
* An introduction to Servlet 3.0 and Java 6 (TC JUG)
* (c) Software Engineering Solutions, Inc.
*/

@WebServlet(name="HelloWorldServlet", urlPatterns={"/foo", "/bar"})
public class HelloWorldServlet extends HttpServlet {
	private static final Logger logger =
		Logger.getLogger("com.swengsol");
	protected void doGet(HttpServletRequest request,
	  HttpServletResponse response)
	  throws ServletException, IOException {
		logger.info("Within request>>>" + getServletName());
		Squawker squawker =
		new Squawker("HelloWorldServlet: annotations map to " +
			"url patterns /foo and /bar: " + new Date());
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.println(squawker.getHTML());
	}
}

The final annotation of interest is @WebListener, which we demonstrate using a trivial context listener. Registering a different listener is just as simple. You add this annotation to any class that implements a listener interface, and you are in business.

package com.swengsol.listeners;
/**
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 10:48:14 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import java.util.EnumSet;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

@WebListener
public class MyServletContextListener implements ServletContextListener {
    private static final Logger logger =
			Logger.getLogger("com.swengsol");

    // Public constructor is required by servlet spec
    public MyServletContextListener() {
    }
    public void contextInitialized(ServletContextEvent sce) {
        logger.info("Context Listener > Initialized");
    }
    public void contextDestroyed(ServletContextEvent sce) {
    }
}

So is the web.xml completely redundant? Not quite.

You can still use the web.xml to specify the ordering of components such as filters.

Likewise, you would use it when you wanted to override any configuration settings that may have been specified via annotations.

In just a bit, we’ll look at the programmatic definition of servlets and filters.

I’ll be speaking at the Twin Cities Java Users Group tomorrow.

I hope to meet a number of people from my former team, and I do hope some of my new teammates will come out as well.

In case you aren’t able to make it, but are interested in learning what I’m going to speak about … here’s a sneak preview.

JSR-315-ServletSpec3.0-Damodar-Chetty-swengsol.com

See you there!

While working on a presentation for JSR 315 – servlet specification 3.0, I realized that a key aspect to understanding asynchronous servlets was to understand how asynchronous processing worked in Java in the first place.

One thing led to another, and soon I was neck deep in executors and executor services – the key building blocks of aysnchronous processing in Java.

In this blog post, I summarize my learnings on this topic.

Concepts

A task is defined as a small independent activity that represents some unit of work that starts at some point, requires some activity or computation, and then terminates. In a web server, each individual incoming request meets this definition. In Java, these are represented by instances of Runnable or Callable.

A thread can be considered to be a running instance of a task. If a task represents some unit of work that needs to be done, then a thread represents the actual performance of that task. In Java, these are represented by instances of Thread.

Synchronous processing occurs when a task must be done in the main thread of execution. In other words, the main program must wait until the current task is done, before it can continue on with its processing.

Asynchronous processing is when the main thread delegates the processing of a task to a separate independent thread. That thread is then responsible for the processing associated with the task, while the main thread returns to doing whatever main programs do.

A thread pool represents one or more threads sitting around waiting for work to be assigned to them. A pool of threads brings a number of advantages to the party. First, it limits the cost of setting up and tearing down threads, since threads in the pool are reused rather than created from scratch each time. Second, it can serve to limit the total number of active threads in the system, which reduces the memory and computing burdens on the server. Finally, it lets you delegate the problem of managing threads to the pool, simplifying your application.

At this point, it is important to note that there are three critical mechanisms at work here – there’s the arrival of tasks to be processed (someone is requesting some units of work to be done), there is the submission of tasks to some holding tank, and then there’s the actual processing of each task. The Executor framework in Java separates the latter two mechanisms – submission and processing.

The arrival of requests is generally out of the control of the program – and may be driven by requests from clients. The submission of a request is typically made by requesting that the task be added to a queue of incoming tasks, while the processing is implemented using a pool of threads that sit idle waiting to be assigned an incoming task to process.

Java 5.0 and Thread Pools

Java 5.0 comes with its own thread pool implementation – within the Executor and ExecutorService interfaces. This makes it easier for you to use thread pools within your own programs.

An Executor provides application programs with a convenient abstraction for thinking about tasks. Rather than thinking in terms of threads, an application now deals simply with instances of Runnable, which it then passes to an Executor to process.

The ExecutorService interface extends the simplistic Executor interface, by adding lifecycle methods to manage the threads in the pool. For instance, you can shutdown the threads in the pool.

In addition, while the Executor lets you submit a single task for execution by a thread in the pool, the ExecutorService lets you submit a collection of tasks for execution, or to obtain a Future object that you can use to track the progress of that task.

Runnable and Callable

The Executor framework represents tasks using instances of either Runnable or Callable. Runnable‘s run() method is limiting in that it cannot return a value, nor throw a checked exception.  Callable is a more functional version, and defines a call() method that allows the return of some computed value, and even throwing an exception if necessary.

Controlling your Tasks

You can get detailed information about your tasks using the FutureTask class, an instance of which can wrap either a Callable or a Runnable. You can get an instance of this as the return value of the submit() method of an ExecutorService, or you can manually wrap your task in a FutureTask before calling the execute() method.

The FutureTask instance, which implements the Future interface, gives you the ability to monitor a running task, cancel it, and to retrieve its result (as the return value of a Callable‘s call() method).

ThreadPoolExecutor

The most common implementation of ExecutorService that we will encounter is the ThreadPoolExecutor.

Tasks are submitted to a ThreadPoolExecutor as instances of Runnable. The executor is then responsible for the actual processing, and your application no longer needs to care about what happens behind that abstraction.

This executor is defined in terms of:

  1. a pool of threads (with a configured number of minimum and maximum threads),
  2. a work queue,
    this queue holds the submitted tasks which are still to be assigned a Thread from the pool. There are two main types of queue – bounded and unbounded.Adding tasks to an unbounded queue always succeeds.A bounded queue (such as a LinkedBlockingQueue with a fixed capacity) rejects tasks once the number of pending tasks reaches its maximum capacity.
  3. a handler that defines how rejections should be handled (the saturation policy).
    When a task cannot be added to a queue, the thread pool will call its registered rejection handler to determine what should happen. The default rejection policy is to simply throw a RejectedExecutionException runtime exception, and it is up to the program to catch the exception and process it. Other policies exist, such as DiscardPolicy, which silently discards the task without any notifications.
  4. a thread factory .
    By default, new threads constructed by the executor will have certain properties – such as a priority of Thread.NORM_PRIORITY, and a thread name that is based on the pool number and thread number within the pool. You can use a custom thread factory to override these defaults.

Algorithm for using an Executor

1.  Create an Executor

You first create an instance of an Executor or ExecutorService in some global context (such as the application context for a servlet container).

The Executors class has a number of convenience static factory methods that create an ExecutorService. For instance, newFixedThreadPool() returns a ThreadPoolExecutor instance which is intialized with an unbounded queue and a fixed number of threads; while newCachedThreadPool() returns a ThreadPoolExecutor instance initialized with an unbounded queue and unbounded number of threads. In the latter case, existing threads are reused if available, and if no free thread is available, a new one is created and added to the pool. Threads that have been idle for longer than a timeout period will be removed from the pool.


private static final Executor executor = Executors.newFixedThreadPool(10);
 

Rather than use these convenience methods, you might find it more appropriate to instantiate your own fully customized version of ThreadPoolExecutor – using one of its many constructors.


private static final Executor executor = new ThreadPoolExecutor(10, 10, 50000L,   TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(100));
 

This creates a bounded queue of size 100, with a thread pool of fixed size 10.

2. Create one or more tasks

You are required to have one or more tasks to be performed as instances of either Runnable or Callable.

3. Submit the task to the Executor

Once you have an ExecutorService, you can submit a task to it using either the submit() or execute() methods, and a free thread from the pool will automatically dequeue the tasks and execute it.

4. Execute the task

The Executor is then responsible for managing the task’s execution as well as the thread pool and queue. Exactly what happens here depends on the thread pool size limits, the number of idle threads, and the bounds of the queue.

In general, if the pool has fewer than its configured number of minimum threads, new threads will be created to handle queued tasks until that limit is reached.

If the number of threads is higher than the configured minimum, then the pool is reluctant to start any more threads. Instead, the task is queued until a thread is freed up to process it. If the queue is full, then a new thread must be started to handle it.

If the number of threads is at the maximum, the pool is unable to start new threads, and hence the task will either be added to the queue, or will be rejected if the queue is full.

The threads in the pool will continually monitor the queue, for tasks to run. Threads that are higher than the configured minimum become ripe for termination if they have been idle for longer than the configured timeout period.

5. Shutdown the Executor

At application shutdown, we terminate the executor by invoking its shutdown() method. You can choose to terminate it gracefully, or abruptly.

C’est le fin!

Bibliography:

Java Concurrency in Practice, Goetz et al

Java Threads, Oaks and Wong

Today I got a chance to play around with building the brand new Tomcat 7.

If you’ve read my book, you know the steps.

To summarize:

1) Get the latest JDK, which right now is at version 6u21. Add {JAVA_HOME}/bin to your path.

2)  Get winmd5sum – those of you who know me are aware of how paranoid i am :)

3) Get Apache Ant, which is currently at 1.8.1. Add your {ANT_HOME}/bin folder to your path.

4) Get the Subversion command line client, which is at 1.6.12.

That’s all you need.

Now, download the latest source to an apporpriate folder on  your workstation:

svn co http://svn.apache.org/repos/asf/tomcat/tc7.0.x/tags/TOMCAT_7_0_0

Finally, change over to the  TOMCAT_7_0_0 folder that was just created. You should find build.xml in there.

Simply type “ant” and sit back as your shiny new Tomcat installation is built.

To start up your new Tomcat build, change directory to the output/build/bin and run startup.bat.

In your browser, mosey on over to http://localhost to access your Tomcat installation.

Compared to building Tomcat 6, I was pleasantly surprised with the ease with which  Tomcat was built from its source.  So far so good with this new iteration.

Eclipse Helios

To get Tomcat to run within Eclipse Helios, I downloaded the 64-bit version of Eclipse 3.6 (eclipse-SDK-3.6-win32-x86_64.zip).

I set up the Eclipse Classpath Variables ANT_HOME and TOMCAT_LIBS_BASE to point to the Ant install folder and the path to where the Ant build downloaded its JARs (c:\usr\share\java, by default).

A couple of warnings are in order here:
1. run the “ant extras” target to download the webservices JARs that are required to build the project in Helios.
2. Rename the “eclipse.project” and “eclipse.classpath” to drop the “eclipse” part of the file name.

Now, add a Run configuration for the org.apache.catalina.startup.Bootstrap class as a Java Application. Run up the application, and go on over to http://localhost:8080 as before.

That’s it!

Now that the basics of garbage collection are behind us, in this post I’ll discuss the Garbage Collectors that are available for us to choose from.

Before we go there, let’s first look at two key measures that will help us evaluate the available garbage collectors. The time spent by an executing application can be expressed as the sum of the time spent by the application in actually doing useful work,  and the time that the application had to forcibly wait for garbage collection activities to complete.

This can be expressed as:

Total Execution Time = Useful Time + Paused Time

This brings us to our definitions:

  1. Throughput:
    This is defined as the percentage of total time that is not spent in garbage collection.  I.e.,  [Useful Time] / [Total Execution Time]
  2. Latency:
    This is defined as the average of all the [Paused Time] values over the execution of the application.

Latency is usually a major concern for highly interactive or real time applications, where a delay in processing is noticeable and potentially significant. On the other hand, for server side web applications, a bigger concern is throughput, since the latency introduced by garbage collection may be dwarfed by the latencies introduced by other contributors such as database or network access.

It is important to note that it is hard for a garbage collector to maximize both measures. For instance, throughput can be enhanced by using a very generously sized young generation (which reduces the frequency at which GC cycles are run). However, this can adversely impact latency when the garbage collection does occurs, as the time per garbage collection cycle is directly proportional to the size of the area of the heap being managed.

Garbage Collectors

The following garbage collectors are available for our use, and can be configured using the appropriate JVM switches.

Generational Area Characteristics
Serial Young Stop The World, Copying Collector, Single GC thread. (works as described in the previous article).
Serial Old (MSC) Old Stop the World, Mark Sweep Compact (MSC), Single GC thread
Parallel Scavenge Young Stop the World, copying collector, multiple GC threads. Provides higher throughput by executing GC tasks in parallel with each other (but not the app).

Cannot run during concurrent phases of the CMS.

Parallel New Young As Parallel Scavenge, but can run during the concurrent phases of the CMS
Parallel Old/ Parallel Compacting Old Similar to Parallel Scavenge, but operates on the old generation.

uses multiple GC threads to speed up the work of Serial Old (MSC).

STW collector, but higher throughput for old generation collections.

Concurrent Mark-Sweep (CMS) Old Breaks up its work into phases, and executes most of its phases concurrently with the application thread – resulting in low latency. However, it introduces substantial management overhead and results in a fragmented heap.

Selecting a Garbage Collector

It is important to note that you can install different collectors to manage each generation. For instance, to use the Parallel Scavenge collector for the Young Generation, and the Serial Old collector for the Old Generation, you would use the following switch:

java -XX:+UseParallelGC

Switch Young Generation Old Generation
UseSerialGC Serial Serial Old (MSC)
UseParNewGC ParNew Serial Old (MSC)
UseConcMarkSweepGC ParNew CMS (mostly used)

Serial Old (used when concurrent mode failure occurs)

+UseParallelGC Parallel Scavenge Serial Old
UseParallelOldGC Parallel Scavenge Parallel Old
+UseConcMarkSweepGC
-UseParNewGC
Serial CMS
Serial Old

Performance Tuning Considerations

While tuning is largely trial-and-error, and is highly dependent on your particular environment and application needs, there are a few guiding principles that might be of help.

  1. An insufficient heap is the leading cause of garbage collection. This is particularly a problem for server side JVMs, especially at high loads. Hence, devote as much space to the heap as possible. Try allocating between 50-70% of the physical memory on the server to the JVM and see if it makes a difference.
  2. Set the initial and maximum heap sizes to the same value. You’re likely going to end up at your maximum value anyway – so why not make it easier on the JVM – and avoid having to gradual grow your heap? This eliminates the CPU cycles required to grow the heap.
  3. Set the Young Generation size appropriately. It has to be small enough (to avoid lengthy GC pauses), but big enough to accommodate a large number of transitory objects. Use the NewSize and MaxNewSize parameters wisely, and set the young generation to about 25% of the total heap. You can also use NewRatio to set the size of the young generation relative to the old generation.
  4. The Young Generation area must be set to less than half the total heap (see Reference [1] for details on the Young Generation guarantee).
  5. Use the default Garbage Collectors and attempt some of the more complex options only if the situation warrants it.
  6. Ensure that you clear out references that are no longer needed. Pay particular attention to collections (such as maps) that may continue to hold obsolete references to objects, long after their usefulness has ended.
  7. Use JVM options like -verbose:gc, and -XX:+PrintGCDetails to monitor GC performance. Ideally, you want to avoid a sawtooth pattern, which large amounts of memory being freed up after each collection.

With this, I’ve come to the end of the story I set out to tell about garbage collection in Java. This question was prompted by an attendee at my presentation at SuperValu, Inc. in Chanhassen.

Do add a comment here if you find anything here that merits correction.

References:

  1. http://java.sun.com/docs/hotspot/gc1.4.2/
  2. http://blogs.sun.com/jonthecollector/entry/our_collectors
  3. http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

The image below demonstrates what the JVM heap might look like after an application has been running for some time.

As we saw in the last article, the JVM’s heap is divided into 3 main areas – the permanent generation (purple), the old generation (yellow), and the young generation. The young generation area is further subdivided into Eden (green), and two survivor spaces (blue and orange).

The root set of an application is a set of objects that define the highest level references available to the application. The most common members of this set are any static references available to the application, as well as any local variable references to objects that have been allocated by the application itself.

An object on the heap is considered to be “live” if a path can be traced from a root set member to that given object; otherwise the object is considered “dead”. Live objects are said to have passed the “reachability” test, whereas dead objects have failed that test. Live objects are important and must be preserved, whereas dead objects are considered garbage, and must be reclaimed during the next garbage collection cycle.

In the image below, live objects are indicated by a bright brick pattern, while dead objects are represented using a washed out wavy pattern.

We will use this diagram for further exploration of the GC mechanism.

Garbage collectors can typically be described using these dimensions:

  1. Tracing garbage collectors
    This describes a collector that relies on the reachability test to determine which objects should be preserved, and which ones are garbage and so need to be reclaimed.
  2. Stop the World or Concurrent collectors
    Collectors often rely on the fact that no mutations of the heap may occur once the garbage collector has begun its operation. A Stop the World collector freezes all activity in the JVM until it has completed its cycle. On the other hand, a concurrent collector attempts to run the garbage collection process concurrently with the running application. Allowing concurrent operation ratchets up the complexity of its implementation significantly. In addition, such collectors may not be as aggressive at cleaning up garbage as Stop the World collectors.
  3. Compacting collectors
    As memory allocations and deallocations occur over the life of an application, the heap tends to get rather fragmented. This degrades the ability of the JVM to satisfy requests for large contiguous blocks of memory. Compacting collectors address this by defragmenting the heap – by moving live objects so that they are adjacent to each other, maximizing the contiguous free space available on the heap. This results in more efficient memory allocation.

    An alternative to compacting is to allow an object to span non contiguous blocks of memory. The tradeoff is increased implementation complexity and memory management overhead.

  4. Generational Collectors
    Most objects allocated by an application are short lived. Usually, these objects survive only for the duration of a single method call, before being eligible for reclamation.

    Further, the effort required to manage memory is directly proportional to the size of the memory block that needs to be managed. In other words, the smaller the area to be managed, the faster the collection will complete, thereby increasing the amount of CPU time available to the application itself.

    A generational collector takes advantage of both these principles.

    First, it divides the heap into multiple areas – to reduce the area that must be combed during a garbage collection cycle.

    Second, it ensures that each area holds objects of a given generation. The permanent generation hold objects that are relatively permanent; the old generation holds objects that are considered elderly; and the young generation holds objects that are relative newcomers (either newborn or middle aged). This ensures that most of the collection activity can be focused on the small area of the heap that contains the volatile young generation; with old generation collection being required only rarely.

Garbage collectors in the Java world, contain one or more of the above characteristics. For instance, the standard serial collector is a generational, tracing, Stop-the-World, and compacting, type of collector.

The Young Generation area is sub divided further into Eden and two Survivor spaces. At any given time, there is only one “active” survivor space (labeled “From”). The inactive space is labeled “To”. After each successful garbage collection cycle within the Young Generation, the active and inactive survivor spaces switch roles.

Let us assume that 2 new allocations (the green checkerboard pattern) are being requested by the application. If there is enough memory available in Eden, the allocation is made in Eden (as shown), and the application proceeds with no latency being experienced.

The diagram shows that the first allocation succeeded and now resides on the heap.

However, the second allocation request was larger than available space in the Eden! The JVM is unable to fulfill the request, and so it awakens the garbage collector to come to its aid. This results in a Young Generation collection cycle.

The Young Generation collector begins by performing the reachability test on all objects in Eden and in the currently active Survivor space (labeled From). The live objects are identified using the reachability test. Next, it begins copying the active objects out into either the inactive Survivor space (if the object is fairly new) or into the Old Generation area (if the object has survived a number of previous young generation collections). This results in the heap as shown:

A few things to note here:

  1. The newly allocated object is created in Eden (as we’d expect)
  2. The active and inactive Survivor spaces switch roles (and are re-labeled) at the end of the garbage collection cycle.
  3. The previous contents of the Young Generation [Eden + previous From] have now been copied over either to the inactive Survivor space or to the Old Generation area. Here, 2 middle-aged active objects (blue) from the previous From, and 2 newborn active objects (green) from Eden have been copied over to the inactive Survivor space; and 1 elderly active object (blue) from the previous From has been copied over to the Old Generation.
  4. The requested object allocation (checkerboard green) was now satisified from Eden, and it now resides there.
  5. Both Eden and the previously inactive survivor space (To) are nicely defragmented, with active objects on one side and free space on the other. (I’ve not shown the areas marked as garbage in these areas).

This is a fairly quick and painless collection operation, and even if the collector were to stop the world, the pause would be rather unnoticeable. Hence, a Young Generation collection is also termed a “Minor Collection”.

So, what happens when the Old Generation itself becomes full? Let’s reimagine our heap as shown below, with a new object allocation waiting to be satisfied.

In this case, a Young Generation collection is called for because there isn’t enough space available in Eden to satisfy this allocaiton request. However, unlike the earlier scenario, the promotion of the middle-aged object from the active Survivor space to being an elderly object in the old generation cannot proceed because there is no free space available in the Old Generation. In this case, the Young Generation collection is put on hold, while an Old Generation collection cycle is spun up to free up space in the Old Generation.

This results in what is termed a Major Collection, since this activity is expensive (given the size of the entire heap), and the pause suffered by the application (for Stop The World collectors) is noticeable.

However, in the end, the net result of the heap should be exactly as shown as the result of the Young Collection.

This ends part 2 of this series.

Continue on to part 3 >

Garbage collection in the JVM is often treated as a dark art. We know that we’re supposed to be thankful to the JVM for freeing us from worrying about the intricacies of memory management. At the same time, we’d like to retain some amount of control over this process as well. The challenge for most developers is that we’re not sure how.

In this series of posts, I’m going to discuss the garbage collection mechanisms available in Java 6, and how we might train it to do our bidding.

Languages such as C required the programmer to be keenly aware of the memory requirements of a program. You knew exactly how many bytes you needed for a data structure, as well as how to request the operating system for those bytes in memory. With that kind of power came the responsibility of ensuring that you freed this memory once you were done with it. Without the explicit freeing of this memory, the data structure was locked in memory, remaining unavailable both to your program as well as to the operating system. It is easy to imagine how a poorly written program could starve itself by being profligate in its misuse of memory.

A new world order was established with the introduction of Java and the managed memory model it introduced. No more did the application control the allocation and freeing of memory – all that was now the purview of the virtual machine. All that an application did was use the new operator to allocate an object, and all the magic happened behind the scenes. Not only was the memory allocated automatically from the heap, but also was freed automatically whenever that object was no longer needed. This article describes the magic behind this mechanism. The Java heap is an area in memory that is allocated to the virtual machine, and is used to meet the memory needs of a running application. This block of memory is specified using the -Xms and -Xmx VM parameters, as shown:

java -Xms256m -Xmx512m …

This informs the java interpreter that we are requesting a starting heap size of 256MB. If the application’s memory needs exceed that limit, then the JVM may request additional memory from the operating system, until the maximum limit is reached, at 512MB. If an application requires memory beyond this maximum limit, then an Out of Memory error will result. An optimization is to set both these values to the same number. This ensures that the maximum allowable memory is allocated at one shot, and no further dynamic expansion of the heap has to happen.

Heap Structure

The JVM’s heap is not simply a linear byte array. Instead, it is comprised of the following 3 areas:

Permanent Area

This area contains Class and  Method objects for the classes required by the application. This area is not constrained by the limit imposed by the -Xmx parameter.

The size of this area is managed using the -XX:PermSize and -XX:MaxPermSize JVM parameters. The former sets the initial size, while the latter sets the maximum size of this area. Again, in order to prevent the dynamic growing of this space, and the resulting slowdown as the garbage collector kicks in, you could set both these parameters to the same value. Further, make sure you set this space large enough to hold all the classes needed by your application – else your application will fail with an error that indicates that you are out of PermGen space – even though your heap may have plenty of headroom available. This area was called “permanent” because older JVMs (prior to 1.4) would never garbage collect this area. Objects loaded into here were locked in place until the JVM exited. Newer VMs provide the -noclassgc parameter that lets you tune this behavior. If this parameter is not set, the JVM will garbage collect within this area if it needs memory, especially during a Full Collection cycle (we’ll see more about this in a bit).

Young Generation Area

Most objects created by an application are ephemeral – they only live for a very short period of time. It makes sense therefore for such objects to be confined to a fairly small sandbox that can be combed through on a very frequent basis. This improves the efficiency of the collection operation for two reasons – first, collections tend to be much faster when the area to comb is small; and second, the results of a collection tend to be much more productive as most of the objects created here are short lived and so their space can be readily reclaimed.

Old Generation Area

This area generally contains objects that are fairly long lived, i.e., those that have survived multiple collection cycles within the young generation area. The idea behind promoting long lived objects here is to avoid the overhead of continually managing these objects in the young generation area. I.e., it helps optimize the young generation collections to not have to bother with objects that are known to be long lived. This is often much larger than the new generation area, and so garbage collection is much more involved here.

<End of part 1>

Continue on to part 2 >

Powered by WordPress Web Design by SRS Solutions © 2012 Damodar's Musings Design by SRS Solutions