Can't instantiate anonymous class more than 16 times

Wei Yin Teo weiyinteo at gmail.com
Mon Aug 10 15:49:40 PDT 2009


Right, I think the work around is working because we are getting a new  
class and we don't hit the threshold.

The magic number 15 is the ReflectionFactory.inflationThreshold() as  
we can see in the class NativeConstructorAccessorImpl


  public Object newInstance(Object[] args) ...    {
         if (++numInvocations >  
ReflectionFactory.inflationThreshold()) {
             ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
                 new MethodAccessorGenerator().
                     generateConstructor(...)
	...

I think the AnonymousClassLoader mangles the class name from  
InstanceTest to InstanceTest/123456. However the generated  
ConstructorAccessor would interpret that as a class InstanceTest. 
123456 instead of InstanceTest and the JVM would then try to load  
InstanceTest/123456.class. Of course it can't be found anywhere. I  
suppose Class.forName() should not be able to locate it in the  
system(permGen?) name space, either.

On further note, I can't load an anonymous class which subclass  
another anonymous class too; because the class loader can't find the  
super class. I am not too sure about how the class loading mechanism  
plays with anonymous classes, especially how do we maintain an  
anonymous class hierarchy.

Thanks,
Wei


On 10 Aug 2009, at 23:19, Rémi Forax wrote:

> Le 10/08/2009 23:54, Rémi Forax a écrit :
>>
>> Le 10/08/2009 21:56, Wei Yin Teo a écrit :
>>>
>>> Hi,
>>>
>>> After loading an anonymous class through the AnonymousClassLoader,  
>>> I could construct the object by calling the newInstance on the  
>>> class. But the 16th time failed. Here is the code and stack trace
>>
>> hum, perhaps a bug,
>> could you try with :
>>
>> AnonymousClassLoader acl = new  
>> AnonymousClassLoader(LoadingTest.class);
>>
>> cheers,
>> Rémi
>
> Forget what I've written.
> I am able to reproduce the bug.
> It seems you can't create more than 16 instances of an anonymous  
> class,
> a really weird bug, isn't it.
>
> The known workaround is to create one class by instance :(
>
>     ...
>     byte[] classBytes = getClassBytes();
>     for (int i = 0; i < 100; i++) {
>       Class<?> testClass = acl.loadClass(classBytes);
>       try {
>         testClass.newInstance();
>       }
>     ...
>
> Rémi
>
>>
>>>
>>> class LoadingTest {
>>>
>>>  public void testLoading() {
>>>  AnonymousClassLoader acl = new AnonymousClassLoader();
>>>
>>>  Class<?> testClass = acl.loadClass(getClassBytes());
>>>
>>>   for (int i = 0; i < 100; i++) {
>>>  try {
>>>  testClass.newInstance();
>>>  }
>>>  catch(Throwable e) {
>>>  System.out.println("failed at " + i);
>>>  e.printStackTrace();
>>>  throw e;
>>>  }
>>>  }
>>>    }
>>>
>>>    private byte[] getClassBytes() {
>>>  ClassWriter cw = new ClassWriter(0);
>>>  MethodVisitor mv;
>>>
>>>  cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "InstanceTest", null,
>>>  "java/lang/Object", null);
>>>  mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
>>>  mv.visitCode();
>>>  Label l0 = new Label();
>>>  mv.visitLabel(l0);
>>>  mv.visitVarInsn(ALOAD, 0);
>>>  mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",  
>>> "()V");
>>>  mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
>>>  "Ljava/io/PrintStream;");
>>>  mv.visitLdcInsn("constructed");
>>>  mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
>>>  "(Ljava/lang/String;)V");
>>>  mv.visitInsn(RETURN);
>>>  Label l1 = new Label();
>>>  mv.visitLabel(l1);
>>>  mv
>>>  .visitLocalVariable("this",
>>>  "Ltest/com/gs/s4j/misc/AnonymousClassLoading;", null,
>>>  l0, l1, 0);
>>>  mv.visitMaxs(2, 1);
>>>  mv.visitEnd();
>>>  cw.visitEnd();
>>>  return cw.toByteArray():
>>>   }
>>> }
>>>
>>> It appears at the 16th time, the JVM generate a  
>>> ConstructorAccessor and it does not know how to handle anonymous  
>>> class.
>>>
>>> Thanks,
>>> Wei
>>>
>>> Here is the output from the code.
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> = 
>>> ====================================================================
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> constructed
>>> failed at 16
>>> java.lang.NoClassDefFoundError: InstanceTest/7572081
>>>  at sun.reflect.GeneratedConstructorAccessor3.newInstance(Unknown  
>>> Source)
>>>  at  
>>> sun 
>>> .reflect 
>>> .DelegatingConstructorAccessorImpl 
>>> .newInstance(DelegatingConstructorAccessorImpl.java:45)
>>>  at java.lang.reflect.Constructor.newInstance(Constructor.java:539)
>>>  at java.lang.Class.newInstance0(Class.java:372)
>>>  at java.lang.Class.newInstance(Class.java:325)
>>>  at  
>>> test 
>>> .com 
>>> .gs 
>>> .s4j 
>>> .misc.AnonymousClassLoading.testLoading(AnonymousClassLoading.java: 
>>> 47)
>>>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>  at  
>>> sun 
>>> .reflect 
>>> .NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>>>  at  
>>> sun 
>>> .reflect 
>>> .DelegatingMethodAccessorImpl 
>>> .invoke(DelegatingMethodAccessorImpl.java:43)
>>>  at java.lang.reflect.Method.invoke(Method.java:623)
>>>  at junit.framework.TestCase.runTest(TestCase.java:164)
>>>  at junit.framework.TestCase.runBare(TestCase.java:130)
>>>  at junit.framework.TestResult$1.protect(TestResult.java:106)
>>>  at junit.framework.TestResult.runProtected(TestResult.java:124)
>>>  at junit.framework.TestResult.run(TestResult.java:109)
>>>  at junit.framework.TestCase.run(TestCase.java:120)
>>>  at  
>>> org 
>>> .eclipse 
>>> .jdt 
>>> .internal 
>>> .junit 
>>> .runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
>>>  at  
>>> org 
>>> .eclipse 
>>> .jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>>>  at  
>>> org 
>>> .eclipse 
>>> .jdt 
>>> .internal 
>>> .junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>>>  at  
>>> org 
>>> .eclipse 
>>> .jdt 
>>> .internal 
>>> .junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>>>  at  
>>> org 
>>> .eclipse 
>>> .jdt 
>>> .internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java: 
>>> 390)
>>>  at  
>>> org 
>>> .eclipse 
>>> .pde 
>>> .internal 
>>> .junit 
>>> .runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:62)
>>>  at  
>>> org 
>>> .eclipse 
>>> .pde 
>>> .internal 
>>> .junit.runtime.CoreTestApplication.run(CoreTestApplication.java:23)
>>>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>  at  
>>> sun 
>>> .reflect 
>>> .NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>>>  at  
>>> sun 
>>> .reflect 
>>> .DelegatingMethodAccessorImpl 
>>> .invoke(DelegatingMethodAccessorImpl.java:43)
>>>  at java.lang.reflect.Method.invoke(Method.java:623)
>>>  at  
>>> org 
>>> .eclipse 
>>> .equinox 
>>> .internal 
>>> .app 
>>> .EclipseAppContainer 
>>> .callMethodWithException(EclipseAppContainer.java:574)
>>>  at  
>>> org 
>>> .eclipse 
>>> .equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java: 
>>> 196)
>>>  at  
>>> org 
>>> .eclipse 
>>> .core 
>>> .runtime 
>>> .internal 
>>> .adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java: 
>>> 110)
>>>  at  
>>> org 
>>> .eclipse 
>>> .core 
>>> .runtime 
>>> .internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java: 
>>> 79)
>>>  at  
>>> org 
>>> .eclipse 
>>> .core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
>>>  at  
>>> org 
>>> .eclipse 
>>> .core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
>>>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>  at  
>>> sun 
>>> .reflect 
>>> .NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>>>  at  
>>> sun 
>>> .reflect 
>>> .DelegatingMethodAccessorImpl 
>>> .invoke(DelegatingMethodAccessorImpl.java:43)
>>>  at java.lang.reflect.Method.invoke(Method.java:623)
>>>  at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
>>>  at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
>>>  at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
>>>  at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
>>> Caused by: java.lang.ClassNotFoundException: InstanceTest.7572081
>>>  at  
>>> org 
>>> .eclipse 
>>> .osgi 
>>> .internal.loader.BundleLoader.findClassInternal(BundleLoader.java: 
>>> 494)
>>>  at  
>>> org 
>>> .eclipse 
>>> .osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:410)
>>>  at  
>>> org 
>>> .eclipse 
>>> .osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:398)
>>>  at  
>>> org 
>>> .eclipse 
>>> .osgi 
>>> .internal 
>>> .baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java: 
>>> 105)
>>>  at java.lang.ClassLoader.loadClass(ClassLoader.java:331)
>>>  ... 41 more
>>>
>>>
>>>
>>> _______________________________________________
>>> mlvm-dev mailing list
>>> mlvm-dev at openjdk.java.net
>>> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>>>
>>
>>
>> _______________________________________________
>> mlvm-dev mailing list
>> mlvm-dev at openjdk.java.net
>> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>>
>
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20090810/1cc52ab9/attachment.html 


More information about the mlvm-dev mailing list