NOTE
This is not a Groovy related problem, but I’m using it to illustrate my problem and solution here.
PROBLEM
I recently tried mixing some Groovy code into my existing JEE project. I created a simple POGO that looks as sophisticated as this:-
class GroovyStuff { String name }
Then, I configured one of my controllers to invoke that POGO:-
@Controller @RequestMapping(value = "/") public class HomeController { @RequestMapping(method = RequestMethod.GET) public String main() { GroovyStuff stuff = new GroovyStuff(); stuff.setName("Hello Groovy"); System.out.println(stuff.getName()); return "home"; } }
After starting up Jetty, I hit that controller from the web and I get this infamous exception:-
java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.findBootstrapClass(Native Method) at java.lang.ClassLoader.findBootstrapClassOrNull(ClassLoader.java:926) at java.lang.ClassLoader.loadClass(ClassLoader.java:297) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:230) at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:407) at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:383) at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2475) at java.lang.Class.getDeclaredMethods(Class.java:1818) at org.codehaus.groovy.reflection.CachedClass$3$1.run(CachedClass.java:84) at java.security.AccessController.doPrivileged(Native Method) at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:81) at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:79) at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:250) at org.codehaus.groovy.runtime.m12n.SimpleExtensionModule.createMetaMethods(SimpleExtensionModule.java:111) at org.codehaus.groovy.runtime.m12n.SimpleExtensionModule.getMetaMethods(SimpleExtensionModule.java:93) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerExtensionModuleFromProperties(MetaClassRegistryImpl.java:192) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerExtensionModuleFromMetaInf(MetaClassRegistryImpl.java:174) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerClasspathModules(MetaClassRegistryImpl.java:156) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:111) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:73) at groovy.lang.GroovySystem.<clinit>(GroovySystem.java:33) at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:162) at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:192) at myproject.bean.GroovyStuff.$getStaticMetaClass(Stuff.groovy) at myproject.bean.GroovyStuff.<init>(Stuff.groovy) at myproject.controller.HomeController.main(HomeController.java:14) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
I tried both GMaven Plugin and Groovy-Eclipse Compiler Plugin, and both gave me the same problem.
I checked my MAVEN_OPTS
variable, and I have set a rather big max perm size, but it doesn’t fix the problem.
export MAVEN_OPTS="-Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m"
Then, I rebooted my laptop since that’s what most tech supports in the world would tell me to do when they encounter a problem… but it doesn’t fix the problem.
When I commented out the Groovy calls from the controller, everything works fine:-
@Controller @RequestMapping(value = "/") public class HomeController { @RequestMapping(method = RequestMethod.GET) public String main() { //GroovyStuff stuff = new GroovyStuff(); //stuff.setName("Hello Groovy"); //System.out.println(stuff.getName()); return "home"; } }
After venting my frustration at the ping pong table and cursing at the laptop for many hours both at work and at home, I decided to run Jetty directly from the command line:-
mvn clean jetty:run
I was rather surprised that I no longer see the error.
SOLUTION
After poking around, I realized that IntelliJ doesn’t seem to honor my MAVEN_OPTS
setting. When I run jetty:run
goal from IntelliJ, I see the following output in the console:-
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -Dmaven.home=/usr/local/apache-maven-3.0.3 -Dclassworlds.conf=/usr/local/apache-maven-3.0.3/bin/m2.conf -Didea.launcher.port=7533 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 12.app/bin" -Dfile.encoding=UTF-8 -classpath "/usr/local/apache-maven-3.0.3/boot/plexus-classworlds-2.4.jar:/Applications/IntelliJ IDEA 12.app/lib/idea_rt.jar" com.intellij.rt.execution.application.AppMain org.codehaus.classworlds.Launcher --fail-fast --strict-checksums org.mortbay.jetty:jetty-maven-plugin:8.1.8.v20121106:run
So, I went to IntelliJ’s Preferences... -> Maven -> Runner
and set my MAVEN_OPTS
values under VM Options
:-
When I run jetty:run
goal from IntelliJ again, now I see the following output in the console:-
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m -Dmaven.home=/usr/local/apache-maven-3.0.3 -Dclassworlds.conf=/usr/local/apache-maven-3.0.3/bin/m2.conf -Didea.launcher.port=7534 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 12.app/bin" -Dfile.encoding=UTF-8 -classpath "/usr/local/apache-maven-3.0.3/boot/plexus-classworlds-2.4.jar:/Applications/IntelliJ IDEA 12.app/lib/idea_rt.jar" com.intellij.rt.execution.application.AppMain org.codehaus.classworlds.Launcher --fail-fast --strict-checksums org.mortbay.jetty:jetty-maven-plugin:8.1.8.v20121106:run
Now, when I hit my controller again, the error went away.
The moral of the story is… if you still cannot fix your coding problem after spending many hours, go play ping pong.