Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-8035

Class unloading (PermGen) memory leak with Groovy Shell

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.4.7
    • 2.4.8
    • None
    • None
    • Oracle JDK6, Oracle JDK7

    Description

      The following code causes a memory leak in perm gen reproducibly on Oracle JDK6 and 7.

      import groovy.lang.GroovyShell;
      
      public class Demo {
      
      
          public static void main(String[] args) throws Exception {
              for (int i = 0; i < 10000000; i++) {
                  GroovyShell gs = new GroovyShell();
                  Script script = gs.parse(" 'Hello, World';");
                  Object result = script.run();
                  assert result.equals("Hello, World");
              }
          }
      }
      

      Tested with the following VM options (with PermGen size 20MB), the execution results in java.lang.OutOfMemoryError: PermGen space after a little more than 2000 iterations.

      -verbose:class -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+CMSClassUnloadingEnabled -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+TraceClassUnloading -XX:MaxPermSize=16M -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:-UseParNewGC
      

      As a workaround, calling the following method with script.getClass() from above (as described in http://stackoverflow.com/a/41473210/2156613) seems to avoid this leak and trigger class unloading correctly:

          public static void clearAllClassInfo(Class<?> type) {
              try {
                  Field globalClassValue = ClassInfo.class.getDeclaredField("globalClassValue");
                  globalClassValue.setAccessible(true);
                  GroovyClassValue classValueBean = (GroovyClassValue) globalClassValue.get(null);
                  classValueBean.remove(type);
              } catch (Exception ex) {
                  throw new RuntimeException(ex);
              }
          }
      

      This should be handled by Groovy itself, or (if this is not possible) there should be at least a possibility to trigger this functionality via a Groovy API call instead of having to create the above method in all applications using Groovy.

      Attachments

        Activity

          People

            jwagenleitner John Wagenleitner
            gbauer Gernot R. Bauer
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: