groovy
  1. groovy
  2. GROOVY-4154

TemplateServlet with default configuration leaks classes resulting in a PermGen error under Tomcat

    Details

    • Type: Bug Bug
    • Status: Open Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.7.2
    • Fix Version/s: None
    • Component/s: Groovlet / GSP
    • Labels:
      None
    • Number of attachments :
      3

      Description

      TemplateServlet by default uses SimpleTemplateEngine. SimpleTemplateEngine uses a cache to store loaded Template objects. These template objects contain a "script" instance variable that corresponds to the compiled gsp script, the classes are named SimpleTemplateScript[x] where x is a growing number. Problem with this cache is that it is a WeakHashMap. This means that when garbage collection occurs, templates will eventually be removed from the cache-map. It was probably intended so that the cache would empty itself in case heap is running out. Problem is that the ClassLoader that loaded the script classes inside the Template-objects is still kept in memory (by TemplateServlet.engine.groovyShell.loader reference) and this prevents the classes from being garbage collected.

      After the Template object has been removed from the cache by GC and someone request the corresponding gsp template again, TemplateServlet will have to generate a new Template object and because the script classes in templates are generated by passing in a string to the groovyShell, the GroovyClassLoader doesn't recognize that it has already loaded a similar class. In the end, PermGen fills up from the same template classes being compiled multiple times.

      The best fix I've found yet (also the easiest), just use the groovy.text.GStringTemplateEngine instead. It doesn't have this problem. My suggestion for "fixing" the issue would be just to change the default. Maybe even marking SimpleTemplateEngine as "deprecated", unless there are good reasons to use it.

      To reproduce the issue:
      1.download an empty Tomcat instance (I used apache-tomcat-5.5.27)
      2.empty webapps folder
      3.to speed up testing, configure tomcat with restricted heap and permgen with following JAVA_OPTS:
      JAVA_OPTS="
      -verbose:gc
      -Xmx64M
      -XX:MaxPermSize=30M
      -XX:+PrintGCDetails
      -XX:+PrintGCTimeStamps
      -XX:+HeapDumpOnOutOfMemoryError
      -Xloggc:gc.log
      -XX:HeapDumpPath=dump.hprof
      "
      4.copy the attached groovlets.war webapp to the webapps folder (expanded or not, no matter). The webapp contains the default groovlet setup with one index.groovy and one index.gsp that index.groovy dispatches to. Both groovy files are very simple they just print "Hello, groovy!" on a webpage many times.
      5.start tomcat, open jconsole on tomcat pid (optional).
      6.verify installation by calling http://localhost:8080/groovlets/index.groovy you should see "Hello, Groovy multiple times".
      7.view perm gen from jconsole.
      8.repeat cycle:
      a) with your favorite load tester, stress the script (fire multiple threads and multiple http gets).
      For example, with Apache Bench: ab -c 30 -n 10000 "http://localhost:8080/groovlets/index.groovy"
      b) trigger garbage collection from jconsole (Perform GC button)
      c) watch Perm Gen going up slowly

      After 5-10 cycles you either get PermGen error to catalina.out or it just doesn't answer anymore.

        Activity

          People

          • Assignee:
            Unassigned
            Reporter:
            Antti Pöyhönen
          • Votes:
            3 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated: