Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8136353

ClassValue preventing class unloading

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P3
    • Resolution: Not an Issue
    • Affects Version/s: 8, 9
    • Fix Version/s: 9
    • Component/s: core-libs
    • Subcomponent:
    • CPU:
      x86_64
    • OS:
      linux_ubuntu

      Description

      FULL PRODUCT VERSION :
      any JDK supporting ClassValue

      FULL OS VERSION :
      Linux 3.13.0-29-generic #53~precise1-Ubuntu SMP Wed Jun 4 22:06:25 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      ClassValue internal structures seem to prevent the garbage collection of classes, if those keep a reference to the ClassValue instance. I have tested these against several JDK 7, 8 and 9 versions, including for example JDK9 b78. And all of them fail to unload the classes from the supplied jar. It does not matter what class is used to attach a value to (my test uses Integer.TYPE ), nor does it matter if the field is static or not. If the field is changed to use a WeakReferece for example, garbage collection will work.

      This bug is quite problematic for Gradle an Groovy

      THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Yes

      THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      I run the provided CVTest program with very low memory settings for total memory/permgen. I tested with 4m and got a OOME afer less then 100 iterations. For this there has to be a "t/t.jar" with the test classes Dummy and MyClassValue.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Since the controlling program CVTest does not keep any references to the class from t.jar or the ClassValue, all of this must be due for garbage collection at some point. Instead an OOME is thrown.
      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------

      public class CVTest {

          public static void main(String[] args) throws Throwable {
              for (long i = 0; i<10000000; i++) {
                  File dir = new File("t/t.jar");
                  URLClassLoader classLoader = new URLClassLoader(new URL[]{dir.toURI().toURL()});
                  ClassValue cv = (ClassValue) classLoader.loadClass("MyClassValue").newInstance();
                  Object value = cv.get(Integer.TYPE);
                  assert value !=null;
                  assert value.getClass().getClassLoader() == classLoader;
                  classLoader.close();
              }

          }
      }

      And for "t/t.jar":

      public class MyClassValue extends ClassValue {
          protected Object computeValue(Class type) {
              Dummy ret = new Dummy();
              Other.o = this;
              return ret;
          }
      }

      class Dummy {
        static Object o;
      }


      ---------- END SOURCE ----------

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                psandoz Paul Sandoz
                Reporter:
                webbuggrp Webbug Group
              • Votes:
                0 Vote for this issue
                Watchers:
                12 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: