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

annotations cause memory leak

    XMLWordPrintable

    Details

    • Subcomponent:
    • Resolved In Build:
      b51
    • CPU:
      generic
    • OS:
      solaris_8

      Description

      The use of annotation-valued annotation elements causes class loaders that
      contain the annotation types to be retained. This results in a memory leak
      and may prevent the use of annotations in some enterprise applications.

      ==========$ ls -la
      total 28
      drwxr-xr-x 2 gafter 4096 Apr 30 10:03 .
      drwxr-xr-x 17 gafter 4096 Apr 29 22:33 ..
      -rw-r--r-- 1 gafter 113 Apr 30 09:41 A.java
      -rw-r--r-- 1 gafter 23 Apr 30 09:31 B.java
      -rw-r--r-- 1 gafter 29 Apr 30 09:31 C.java
      -rw-r--r-- 1 gafter 3001 Apr 30 09:44 Main.java
      -rw-r--r-- 1 gafter 300 Apr 30 09:58 Makefile
      ==========$ for file in *; do echo //////////////////// $file ; cat -n $file; done
      //////////////////// A.java
           1 public
           2 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
           3 @interface A {
           4 B b();
           5 }
      //////////////////// B.java
           1 public @interface B {}
      //////////////////// C.java
           1 public @A(b=@B()) class C {}
      //////////////////// Main.java
           1 import java.net.*;
           2 import java.lang.ref.*;
           3 import java.util.*;
           4 import java.io.*;
           5
           6 public class Main {
           7 public static void main(String[] args) throws Exception {
           8 for (int i=0; i<100; i++)
           9 doTest(args.length != 0);
          10 }
          11
          12 static void doTest(boolean readAnn) throws Exception {
          13 // URL classes = new URL("file://" + System.getProperty("user.dir") + "/classes");
          14 // URL[] path = { classes };
          15 // URLClassLoader loader = new URLClassLoader(path);
          16 ClassLoader loader = new SimpleClassLoader();
          17 WeakReference<Class<?>> c = new WeakReference(loader.loadClass("C"));
          18 if (c.get() == null) throw new AssertionError();
          19 if (c.get().getClassLoader() != loader) throw new AssertionError();
          20 if (readAnn) System.out.println(c.get().getAnnotations()[0]);
          21 if (c.get() == null) throw new AssertionError();
          22 System.gc();
          23 System.gc();
          24 if (c.get() == null) throw new AssertionError();
          25 System.gc();
          26 System.gc();
          27 loader = null;
          28 System.gc();
          29 System.gc();
          30 if (c.get() != null) throw new AssertionError();
          31 }
          32 }
          33
          34 class SimpleClassLoader extends ClassLoader {
          35 private Hashtable classes = new Hashtable();
          36
          37 public SimpleClassLoader() {
          38 }
          39 private byte getClassImplFromDataBase(String className)[] {
          40 byte result[];
          41 try {
          42 FileInputStream fi = new FileInputStream("classes/"+className+".class");
          43 result = new byte[fi.available()];
          44 fi.read(result);
          45 return result;
          46 } catch (Exception e) {
          47
          48 /*
          49 * If we caught an exception, either the class wasnt found or it
          50 * was unreadable by our process.
          51 */
          52 return null;
          53 }
          54 }
          55 public Class loadClass(String className) throws ClassNotFoundException {
          56 return (loadClass(className, true));
          57 }
          58 public synchronized Class loadClass(String className, boolean resolveIt)
          59 throws ClassNotFoundException {
          60 Class result;
          61 byte classData[];
          62
          63 /* Check our local cache of classes */
          64 result = (Class)classes.get(className);
          65 if (result != null) {
          66 return result;
          67 }
          68
          69 /* Check with the primordial class loader */
          70 try {
          71 result = super.findSystemClass(className);
          72 return result;
          73 } catch (ClassNotFoundException e) {
          74 }
          75
          76 /* Try to load it from our repository */
          77 classData = getClassImplFromDataBase(className);
          78 if (classData == null) {
          79 throw new ClassNotFoundException();
          80 }
          81
          82 /* Define it (parse the class file) */
          83 result = defineClass(classData, 0, classData.length);
          84 if (result == null) {
          85 throw new ClassFormatError();
          86 }
          87
          88 if (resolveIt) {
          89 resolveClass(result);
          90 }
          91
          92 classes.put(className, result);
          93 return result;
          94 }
          95 }
      //////////////////// Makefile
           1 JAVAC=/java/re/j2se/1.5.0/promoted/beta2/b49/binaries/solaris-sparc/bin/javac
           2 JAVA=/java/re/j2se/1.5.0/promoted/beta2/b49/binaries/solaris-sparc/bin/java
           3
           4 all:
           5 mkdir -p classes
           6 $(JAVAC) -d classes A.java B.java C.java
           7 $(JAVAC) Main.java
           8 # this works
           9 $(JAVA) Main
          10 # this fails
          11 $(JAVA) Main foo
      ==========$ make
      mkdir -p classes
      /java/re/j2se/1.5.0/promoted/beta2/b49/binaries/solaris-sparc/bin/javac -d classes A.java B.java C.java
      /java/re/j2se/1.5.0/promoted/beta2/b49/binaries/solaris-sparc/bin/javac Main.java
      Note: Main.java uses or overrides a deprecated API.
      /java/re/j2se/1.5.0/promoted/beta2/b49/binaries/solaris-sparc/bin/javac Main.java
      Note: Main.java uses or overrides a deprecated API.
      Note: Recompile with -Xlint:deprecation for details.
      Note: Main.java uses unchecked or unsafe operations.
      Note: Recompile with -Xlint:unchecked for details.
      # this works
      /java/re/j2se/1.5.0/promoted/beta2/b49/binaries/solaris-sparc/bin/java Main
      # this fails
      /java/re/j2se/1.5.0/promoted/beta2/b49/binaries/solaris-sparc/bin/java Main foo
      @A(b=@B())
      Exception in thread "main" java.lang.AssertionError
              at Main.doTest(Main.java:30)
              at Main.main(Main.java:9)
      make: *** [all] Error 1
      ==========$

        Attachments

          Activity

            People

            Assignee:
            gafter Neal Gafter
            Reporter:
            gafter Neal Gafter
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: