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

Class unloading (PermGen) memory leak with Groovy Shell

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.4.7
    • Fix Version/s: 2.4.8
    • Component/s: None
    • Labels:
      None
    • Environment:
      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

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

              Dates

              • Created:
                Updated:
                Resolved: