Archive for September 7th, 2008

A Grails Memory Leak

Sunday, September 07th, 2008

I’m in the process of building a large database to load-test our application at work. Index usage and execution plans are quite different with many rows than with a few, so I’m creating millions of rows in tables for domain classes that will see a lot of activity to find missing indexes, inefficient queries, etc.

I used the typical strategy for Hibernate batch processing – flush() and clear() the Session periodically to push the data to the database and free up memory used by domain instances. But even with a 1-gig heap, the process kept running out of memory after several hours, and was running very slowly for the last couple of hours – typically indicative of lots of garbage-collection thrashing.

Profiling the process using YourKit showed that domain instance counts were steadily increasing. Repeatedly running gc() had no effect on these instances, although it clearly ran since memory usage and other object counts dropped (note that calls to gc() can’t force garbage collection, it’s just a request).

The code and domain classes aren’t complicated and didn’t have any obvious couplings that could cause instances to not be garbage collected, and I kept ripping out more and more code to try to find what was causing the problem. Finally I got it down to the smallest code block that illustrated the problem:

for (int i = 0; i < 100000; i++) {
   new Thing(name: "thing_${i}")
   Thread.sleep(50) // to allow time to watch things in the profiler
}

I ran this in the Grails console and with Hibernate 2nd-level caching turned off, both in a transaction and not (to eliminate the transaction as the culprit). Just creating the instances and not saving them – in this code Hibernate isn’t involved at all – triggered the problem.

So I described the issue on the Grails User mailing list and after an interesting discussion Graeme mentioned that it had to do with the validation Errors objects. He suggested setting errors to null after the instances were no longer used, i.e

for (int i = 0; i < 100000; i++) {
   Thing thing = new Thing(name: "thing_${i}")
   thing.errors = null
   Thread.sleep(50) // to allow time to watch things in the profiler
}

This should work in a web context, but I was working in the console, so I got a NullPointerException. The problem was clear when I looked at the MetaClass code in DomainClassGrailsPlugin:

static final PROPERTY_INSTANCE_MAP =
     new org.codehaus.groovy.grails.support.SoftThreadLocalMap()

metaClass.setErrors = { Errors errors ->
   def request = RCH.getRequestAttributes()?.request
   def storage = request ? request : PROPERTY_INSTANCE_MAP.get()
   def key = "org.codehaus.groovy.grails.ERRORS_${delegate.class.name}_${System.identityHashCode(delegate)}"
   storage[key] = errors
}

metaClass.getErrors = {->
   def request = RCH.getRequestAttributes()?.request
   def errors
   def storage = request ? request : PROPERTY_INSTANCE_MAP.get()
   def key = "org.codehaus.groovy.grails.ERRORS_${delegate.class.name}_${System.identityHashCode(delegate)}"
   errors = storage[key]
   if(!errors) {
      errors =  new BeanPropertyBindingResult(
              delegate, delegate.getClass().getName())
      storage[key] = errors
   }
   errors
}

Instead of storing the Errors in the Request, which in the console doesn’t exist, it stores it in a Thread-local Commons Collections ReferenceMap. This map doesn’t accept nulls, so instead I had to access it directly, i.e.

DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP.get().clear()

This worked – memory usage was fine and I could see that instances were being garbage-collected while running under the profiler.

But this begs the question – why was I in this mess in the first place? Why are there Errors objects involved if I’m not calling validate() or save(), just creating new instances?

ControllersGrailsPlugin wires up a DataBindingDynamicConstructor that takes a Map to allow creating domain instances like this:

def foo = new Foo(prop1: 123, prop2: 'foo', prop3: new Date())

This dynamic constructor copies the map data using a GrailsDataBinder into the new instance in DataBindingUtils.bindObjectToInstance(), and at the end calls setErrors() passing the BindingResult (which implements Errors) generated from copying the data. These are stored in the Map (or as a Request attribute if running in a web context) and this ended up being the reference that kept the instances from being garbage collection candidates even though they were no longer in scope in the loop.

So, mystery solved. In the end this is all academic for me since I needed to get things working so I rewrote the data population code using JDBC (and Java) and it runs quite a bit faster than the equivalent Grails/Groovy/GORM code. This isn’t usually an issue for small web requests but for a process that takes many hours it definitely makes a difference.

Using GORM outside of Grails part 2 – Swing

Sunday, September 07th, 2008

In an earlier post I wrote about getting GORM to work outside of Grails. It worked, but wasn’t really usable since it could only execute script files, so its usefulness was pretty limited in a real application. Greg Bond replied on the mailing (here and here) with some great enhancements that allowed it to work without script files. So I fleshed that out some more and now have a working implementation and even a Swing application to demonstrate.

The key was that Greg used grails compile to generate his domain class files. I’d just been using the groovyc Ant task, and when I looked at what the Grails compile script the difference turned out to be that Grails uses a Grails-aware subclass of Groovyc, org.codehaus.groovy.grails.compiler.GrailsCompiler. It allows you to specify a resourcePattern attribute to point at the domain class .groovy files for special treatment.

So now instead of one sample project there’s three. One is the gorm standalone project, which creates a jar (gorm_standalone.jar) containing GormHelper which bootstraps GORM. The other two are the sample application, split into GORM domain classes and the Swing application. The domain class application contains the domain class .groovy files plus DataSource.groovy, and most importantly an Ant script that builds a usable jar (domainclasses.jar). The Swing application uses gorm_standalone.jar and domainclasses.jar as libraries and displays a simple UI showing the results of database queries.

Here’s a quick screen shot:

You can download the sample apps here:
GORM standalone app
Sample app domain class app
Sample Swing app

A Grails Plugin for Spring MVC Controllers

Sunday, September 07th, 2008

I wrote earlier about using Spring MVC controllers in a Grails app. I was looking at that again since I thought it might be useful as a plugin. Unfortunately although it did work at the time, I ended up having to do a lot more work to get it going. I guess some things changed in intermediate Grails releases, and I didn’t save the code. But anyway, it’s working now 🙂

Installation

To use it in your app, install like any plugin:

grails install-plugin springmvc

The install script will create a web-app/WEB-INF/jsp folder if it doesn’t exist, and copy the sample error.jsp there if it doesn’t exist. It also creates an empty web-app/WEB-INF/SpringMVC-servlet.xml – the file has to exist but all beans are defined by the plugin or in the app’s resources.groovy and/or resources.xml.

Configuration

There are a few configuration options available – all are optional. They’re defined in a springmvc block in Config.groovy:

Name Default Value Description
urlSuffix ‘action’, i.e. *.action the URL pattern for Spring MVC controller URLs
exceptionMappings none Map with exception class names as keys and JSP names as values
defaultErrorView ‘error’, i.e. web-app/WEB-INF/jsp/error.jsp the default error page if there’s no corresponding mapping for the exception class
interceptors none bean names of HandlerInterceptors to apply to Spring MVC URLs

So a configuration block that defines a single interceptor, uses *.action for URLs, and defines a default error JSP and two exeption-specific exception mappings (note that the values for urlSuffix and defaultErrorView are redundant since they’re the default values) would be:

springmvc {
   interceptors = ['loggingInterceptor']
   exceptionMappings = ['java.io.IOException': 'ioexception']
   exceptionMappings = ['com.myapp.MyException': 'myex']
   defaultErrorView = 'error'
   urlSuffix = 'action'
}

Application Beans

Unlike in Grails, there’s no automatic URL mapping. To connect a controller to a URL you define a Spring bean (in resources.groovy or resources.xml) whose name is the url and the bean class is the controller, e.g.:

   '/test.action'(com.burtbeckwith.mvctest.controller.TestController) {
      cacheSeconds = 0
      bookService = ref('bookService')
   }

This will map http://localhost:8080/yourapp/test.action to TestController. Setting cacheSeconds to 0 instructs Spring to send headers to disable caching. And ‘bookService’ is a dependency injection for BookService to access Book domain instances. The controller returns ‘books’ as it’s view name – this is prefixed by ‘/WEB-INF/jsp/’ and suffixed by ‘.jsp’ to define the JSP that will render the response (i.e. ‘/WEB-INF/jsp/books.jsp’).

You can also define HandlerInterceptors in resources.groovy. They should extend HandlerInterceptorAdapter or implement HandlerInterceptor directly. Add their bean names to the ‘interceptors’ list and Spring MVC requests will be intercepted. Note that these interceptors are in addition to the standard Hibernate OSIV interceptor and a locale change interceptor.

For example:

   loggingInterceptor(com.burtbeckwith.mvctest.interceptor.LoggingInterceptor)

Sample App

You can download a sample app here. It’s pretty simple – it has a single domain class, and a single Grails controller and a Spring MVC controller (to test that both work in the same app). There’s a Grails service to access domain instances that implements a Java interface so it’s callable by the MVC controller. There’s also a sample interceptor (it just logs requests) and a sample JSP 2.0 tag file, date.tag.

The app creates six books in Bootstrap – you can see the data by going to http://localhost:8080/mvctest/test.action. Go to http://localhost:8080/mvctest/regular to access a regular Grails controller.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.